Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Introduction

clojurust is a Rust-hosted dialect of the Clojure programming language. It reads and executes .cljrs and .cljc source files, provides an interactive REPL, and can AOT-compile programs to standalone native binaries.

Goals

  • Interpreter — read and execute .cljrs (native) and .cljc (cross-platform) source files.
  • Reader conditionals.cljc files use #?(:rust ... :clj ... :default ...) to branch on platform; the platform key for clojurust is :rust.
  • Rust interop — Clojure code can call Rust functions through a defined set of conventions and type-marshalling primitives.
  • Garbage collector — a tracing GC manages all Clojure values; an optional region-based allocator is available for allocation-heavy code paths.
  • AOT compilationcljrs compile produces a standalone native binary via Cranelift.

Source file extensions

ExtensionMeaning
.cljrsNative clojurust source. Always evaluated under the :rust platform.
.cljcCross-platform source. Reader conditionals select the active branch; clojurust evaluates :rust branches.

Quick start

cljrs run hello.cljrs
cljrs repl
cljrs eval '(+ 1 2)'
cljrs compile app.cljrs -o app
cljrs test --src-path test

Detailed documentation for each subcommand is in the CLI chapter.

Command-line tool

cljrs is the command-line entry point for clojurust. It provides subcommands for running files, starting a REPL, evaluating expressions, compiling to native binaries, running tests, and managing dependencies.

cljrs [GLOBAL OPTIONS] <SUBCOMMAND> [SUBCOMMAND OPTIONS]

Subcommands

SubcommandDescription
runInterpret a .cljrs or .cljc source file
replStart an interactive REPL
evalEvaluate a single expression and print the result
compileAOT-compile a source file to a native binary
testRun clojure.test namespaces
depsManage project dependencies declared in cljrs.edn
ir-vizRender the optimised IR for a source file to HTML

Global options

These options are accepted by every subcommand.

--stack-size-mb <MB>

Set the main thread’s stack size in megabytes. Defaults to 64 MB. Increase this value if you encounter stack overflows in deeply recursive code.

cljrs --stack-size-mb 128 run my-program.cljrs

--debug

Enable debug-level logging. Prints internal diagnostics to stderr.

--trace

Enable trace-level logging (implies --debug). Much more verbose than --debug.

-X <LEVEL:FEATURES>

Feature-scoped logging. Enables logging at LEVEL for the named comma-separated FEATURES only.

cljrs -X debug:gc,reader run my-program.cljrs
cljrs -X trace:jit run my-program.cljrs

Available levels: debug, trace. Available features: gc, reader, jit, and others.

--gc-stats [FILE]

Print garbage-collector statistics on exit. Pass a file path to write the report there; omit the path to write to stdout.

Only honoured by run, eval, and test.

cljrs --gc-stats run my-program.cljrs       # stats to stdout
cljrs --gc-stats gc.log run my-program.cljrs # stats to file

--verify-commit-signatures

Require valid GPG or SSH signatures on every versioned commit before executing historical code. Off by default. Can also be enabled per-project in cljrs.edn via :verify-commit-signatures true.

Project configuration: cljrs.edn

When any of run, repl, compile, or test starts, clojurust walks up the directory tree from the current working directory and loads the nearest cljrs.edn it finds. The :paths declared in that file are appended to the source-path list (CLI --src-path values come first).

See deps for the full format of cljrs.edn.

cljrs run

Interpret a .cljrs or .cljc source file.

cljrs run [OPTIONS] <FILE>

All top-level forms in FILE are evaluated in order. The return value of the last form is discarded; side effects (output, file writes, etc.) are the intended mechanism for a run program to produce observable results.

Arguments

ArgumentDescription
<FILE>Path to the source file (.cljrs or .cljc)

Options

--src-path <DIR>

Add DIR to the list of directories searched when resolving require. May be repeated to add multiple directories.

cljrs run --src-path src --src-path lib my-program.cljrs

Paths declared in :paths of the nearest cljrs.edn are appended automatically after CLI paths.

--gc-soft-limit-mb <MB>

Soft memory limit for the GC in megabytes. When live heap exceeds this value, a collection is triggered at the next safepoint.

--gc-hard-limit-mb <MB>

Hard memory limit for the GC in megabytes. When live heap exceeds this value, a collection is forced immediately.

Examples

# Run a file in the current directory
cljrs run hello.cljrs

# Run with a source path for namespace resolution
cljrs run --src-path src src/myapp/core.cljrs

# Run and write GC stats to stderr on exit
cljrs --gc-stats run my-program.cljrs

cljrs repl

Start an interactive read–eval–print loop.

cljrs repl [OPTIONS]

The REPL reads one expression at a time, evaluates it, and prints the result. Multi-line input is supported: the REPL continues reading until all open brackets are closed before evaluating.

Type :quit or press Ctrl-D to exit.

Options

--src-path <DIR>

Add DIR to the source-path list for require. May be repeated.

--gc-soft-limit-mb <MB> / --gc-hard-limit-mb <MB>

GC memory limits. See run for details.

REPL behaviour

  • The initial namespace is user.
  • The standard library (clojure.core and friends) is pre-loaded.
  • *1, *2, *3 hold the last three non-nil results.
  • *e holds the last exception.
  • nil results are printed as nil.

Line editing

When clojurust is built with the enable-rustyline feature, the REPL uses rustyline for line editing, including history and readline-style key bindings.

Without that feature, a simpler line reader is used that still supports multi-line input but has no history or key bindings.

Example session

$ cljrs repl
clojurust REPL (type :quit to exit)

=> (+ 1 2)
3
=> (def x 42)
=> x
42
=> (map inc [1 2 3])
(2 3 4)
=> :quit
Bye.

cljrs eval

Evaluate a single Clojure expression and print the result.

cljrs eval '<EXPR>'

The expression is evaluated in a fresh environment with the standard library loaded. If the result is non-nil, it is printed to stdout. A nil result produces no output.

Arguments

ArgumentDescription
<EXPR>The expression to evaluate, as a string

Examples

cljrs eval '(+ 1 2)'
# → 3

cljrs eval '(map str (range 5))'
# → ("0" "1" "2" "3" "4")

cljrs eval '(println "hello")'
# prints: hello
# (println returns nil so no value line is printed)

Notes

eval does not accept --src-path. If you need to require namespaces from a source tree, use run with a small script file instead.

cljrs compile

AOT-compile a source file to a standalone native binary.

cljrs compile [OPTIONS] <FILE> --out <OUT>

The compiler lowers the source file through the IR pipeline and emits a native binary via Cranelift. The resulting binary statically links the clojurust runtime, GC, and standard library; it has no runtime dependency on the cljrs tool.

Arguments

ArgumentDescription
<FILE>Source file to compile (or a directory when --test is used)

Required options

-o, --out <OUT>

Output path for the compiled binary.

Optional options

--src-path <DIR>

Add DIR to the source path for require resolution. May be repeated.

--test

Compile a test harness instead of a regular program. When this flag is set, FILE should be a directory; the compiler discovers all .cljrs/.cljc files in that directory and builds a binary that runs all clojure.test tests found in them.

--gc-soft-limit-mb <MB> / --gc-hard-limit-mb <MB>

GC memory limits baked into the compiled binary, not the compilation process itself.

Examples

# Compile a single file
cljrs compile src/myapp/core.cljrs --out myapp

# Compile and run
cljrs compile src/myapp/core.cljrs --out myapp && ./myapp

# Compile a test binary
cljrs compile --test test/ --out run-tests && ./run-tests

Notes

AOT compilation is based on Cranelift. Not all language features are yet supported in AOT mode; in particular, features that rely on dynamic dispatch or late binding may fall back to interpreted execution within the compiled binary.

cljrs test

Run clojure.test test namespaces.

cljrs test [OPTIONS] [NAMESPACES...]

Loads each namespace, calls clojure.test/run-tests on it, and prints a summary of passes, failures, and errors. Exits with code 0 if all tests pass, 1 if any fail or error, and 2 if no test namespaces are found.

Arguments

ArgumentDescription
[NAMESPACES...]Namespace names to test (e.g. myapp.core-test). If omitted, all namespaces in --src-path directories are discovered automatically.

Options

--src-path <DIR>

Source directory to search for test namespaces. May be repeated. Namespace discovery translates file paths to namespace names by replacing path separators with . and underscores with -.

cljrs test --src-path test

-v, --verbose

Print each passing assertion as well as failures. Useful for identifying which test is hanging.

--gc-soft-limit-mb <MB> / --gc-hard-limit-mb <MB>

GC memory limits. See run for details.

Namespace discovery

When no explicit namespaces are given, cljrs test walks all --src-path directories and converts every .cljrs and .cljc file to a namespace name:

test/myapp/core_test.cljrs  →  myapp.core-test
test/myapp/util_test.cljc   →  myapp.util-test

Output format

Ran 12 tests containing 48 assertions across 2 namespace(s) in 0.3s.
48 passed, 0 failed, 0 errors.

All tests passed.
══════════════════════════════════════════════════════════════

On failure, a breakdown by namespace is printed before the summary line.

Examples

# Run all tests discovered under test/
cljrs test --src-path test

# Run specific namespaces
cljrs test --src-path test myapp.core-test myapp.util-test

# Verbose output
cljrs test --src-path test --verbose

cljrs deps

Manage project dependencies declared in cljrs.edn.

cljrs deps <SUBCOMMAND>

Subcommands

SubcommandDescription
fetchClone or update git dependencies
statusShow which dependencies are cached and which are missing

fetch

cljrs deps fetch [NAME]

Clone or update git dependencies from cljrs.edn. Without a NAME, fetches every git dependency declared in the nearest cljrs.edn. With a NAME, fetches only that one dependency.

Git repositories are cached in ~/.cljrs/cache/git/. Network access only occurs when this command is run explicitly — the runtime never fetches dependencies automatically.

If a versioned symbol or namespace requires a git dependency that is not in the local cache, the runtime raises a clear error:

error: dependency 'my.lib' is not cached locally.
       run `cljrs deps fetch` to download it.

Examples

cljrs deps fetch           # fetch all git deps
cljrs deps fetch my.lib    # fetch only 'my.lib'

status

cljrs deps status

Print the cache status of every dependency declared in the nearest cljrs.edn.

my.lib:    cached (sha: abc1234ef, url: https://github.com/user/my-lib)
dev-tools: NOT cached — run `cljrs deps fetch` (sha: 9f3a112b, url: ...)
vendor:    local dep at ../vendor/utils — ok

Exits with code 0 if all dependencies are satisfied, 1 otherwise.


cljrs.edn format

clojurust discovers project configuration by walking up the directory tree from the current working directory until it finds a cljrs.edn file. The file is valid clojurust EDN:

{:paths ["src" "resources"]

 :deps
 {my.lib    {:git/url "https://github.com/user/my-lib"
              :git/sha "abc1234ef"}
  dev-tools {:git/url "https://github.com/user/dev-tools"
              :git/sha "9f3a112b"}
  vendor    {:local/root "../vendor/utils"}}

 :aliases
 {:dev  {:extra-paths ["dev"]}
  :test {:extra-paths ["test"]
         :extra-deps  {test-tools {:git/url "..."
                                   :git/sha "..."}}}}

 :verify-commit-signatures true}

Keys

KeyTypeDescription
:pathsvector of stringsDirectories to add to the source path. Equivalent to --src-path on the CLI.
:depsmapMap from dependency name (symbol) to dependency descriptor.
:aliasesmapNamed alias maps with :extra-paths and :extra-deps.
:verify-commit-signaturesbooleanIf true, require GPG/SSH signatures on all versioned commits.

Dependency descriptors

Git dependency:

my.lib {:git/url "https://github.com/user/my-lib"
        :git/sha "abc1234ef"}

:git/sha must be at least a 7-character commit prefix. The full commit hash is recommended for reproducibility.

Local dependency:

vendor {:local/root "../vendor/utils"}

:local/root is a path relative to the cljrs.edn file’s directory.

cljrs ir-viz

Render the optimised intermediate representation (IR) for a source file to a self-contained HTML page.

cljrs ir-viz [OPTIONS] <FILE>

The HTML output shows the source side-by-side with the IR, with regions colour-coded by the bump-allocation optimiser’s results. Allocations that did not make it into a region are annotated with their escape verdict and the blamed use site.

This subcommand is primarily a debugging aid for the IR optimisation pipeline.

Arguments

ArgumentDescription
<FILE>Source file to lower to IR

Options

-o, --out <FILE>

Output path for the HTML file. If omitted, the output is written alongside the source file with an .ir.html extension:

src/myapp/core.cljrs  →  src/myapp/core.cljrs.ir.html

--src-path <DIR>

Add DIR to the source path for require resolution. May be repeated.

--quiet

Suppress the [ir-viz] wrote … progress line on stderr.

Example

cljrs ir-viz src/myapp/core.cljrs
# writes: src/myapp/core.cljrs.ir.html

cljrs ir-viz src/myapp/core.cljrs --out /tmp/core.html --quiet

Open the resulting HTML file in a browser to explore the IR.

Interpreting the output

  • Green regions — allocations placed in a bump-allocation region; they do not incur GC heap pressure.
  • Red / yellow annotations — allocations that escaped the region, labelled with the reason (returned, captured by closure, stored in heap object, etc.).
  • Clicking a source line highlights the corresponding IR instructions and vice versa.

Language overview

clojurust is a dialect of Clojure. Its syntax, data model, and core library are designed to be as compatible with Clojure as possible, with a small number of deliberate extensions and a small number of features that are not yet implemented.

What is the same

  • All Clojure literal syntax: symbols, keywords, numbers (long, double, ratio, BigInt, BigDecimal), strings, characters, booleans, nil.
  • All collection literals: list (...), vector [...], map {...}, set #{...}.
  • Reader dispatch macros: ', `, ~, ~@, ^, @, #', #(...), #"...", ##Inf, ##-Inf, ##NaN, tagged literals.
  • The full set of special forms: def, fn*, if, do, let*, loop*, recur, quote, var, set!, throw, try/catch/finally, letfn, binding.
  • Persistent collections (HAMT-backed maps and sets, RRB vectors, linked lists, queues) with Clojure-compatible equality and hashing.
  • clojure.core — arithmetic, comparison, collection operations, lazy sequences, transducers, I/O, concurrency primitives.
  • Standard library namespaces: clojure.string, clojure.set, clojure.test, clojure.walk, clojure.edn, clojure.zip, clojure.data.
  • Protocols (defprotocol, extend-type, extend-protocol), multimethods (defmulti, defmethod), records (defrecord), and reify.
  • Concurrency: atom, future, promise, delay, volatile!, agent.
  • Dynamic variables (binding, with-bindings, *ns*, *out*, etc.).
  • Metadata on vars and some values (with-meta, meta, ^:dynamic, etc.).

Extensions

Known differences and missing features

See Differences from Clojure for the full list.

Reader conditionals

Reader conditionals allow a single source file to contain code for multiple Clojure platforms. clojurust evaluates the :rust branch.

Syntax

Non-splicing form

#?(:rust   expr-rust
   :clj    expr-jvm
   :cljs   expr-clojurescript
   :default expr-fallback)

Exactly one branch is selected at read time based on the current platform. For clojurust, :rust is matched first. If no :rust key is present, :default is used. If neither is present, the entire form is skipped (reads as nothing).

The selected branch is a single expression; the whole #?(...) form evaluates to that expression.

(def platform #?(:rust   "clojurust"
                 :clj    "JVM Clojure"
                 :cljs   "ClojureScript"
                 :default "unknown"))

Splicing form

#?@(:rust   [a b c]
    :clj    [x y z]
    :default [])

The splicing form #?@(...) selects a vector from the active platform and splices its elements into the surrounding form. It is only valid inside a list, vector, map, or set literal.

;; Adds platform-specific items to a vector
(def features [#?@(:rust   [:gc :cranelift]
                   :clj    [:jvm :hotspot]
                   :default [])])
; => [:gc :cranelift]  (on clojurust)
;; Platform-specific require in an ns form
(ns myapp.core
  (:require [clojure.string :as str]
            #?@(:rust [[:clojurust.system :as sys]]
                :clj  [[:java.lang.System :as sys]])))

File-extension behaviour

ExtensionPlatform dispatch
.cljrsAlways :rust. Reader conditionals are still supported but :rust is always the active branch.
.cljcCross-platform. Reader conditional branches are stored as-is; the evaluator selects :rust.

Notes

  • The reader stores all branches of a #?(...) form; only the evaluator discards non-matching branches. This means reader-conditional forms can be inspected programmatically without losing the other branches.
  • Order within a reader conditional matters: keys are checked left-to-right. :default should come last.
  • Unlike Clojure, there is no :cljr (ClojureCLR) platform; the clojurust key is :rust.

Versioned symbols

clojurust lets you pin a symbol or namespace to a specific git commit by appending @<commit> to its name. This lets callers use a historical implementation without requiring the defining library to keep the old code alongside the new.

Syntax

my-fn@abc1234           ; unqualified versioned symbol
my.ns/my-fn@abc1234     ; namespace-qualified versioned symbol

The commit suffix must be a valid hex prefix of at least 7 characters (the full 40-character hash is recommended for reproducibility).

Versioned require

Whole namespaces can be loaded at a specific commit:

(require '[my.lib@abc1234 :as lib-v1])
(require '[my.lib         :as lib])      ; HEAD

(lib/some-fn x)        ; current version
(lib-v1/some-fn x)     ; pinned to abc1234

Both aliases coexist in the same namespace; calls through lib-v1/ always resolve against commit abc1234.

Propagation semantics

When a function body is evaluated in a versioned context — because it was loaded via a versioned require or called through a versioned symbol — the following resolution rules apply:

Symbol formResolved at
Unqualified or same-namespace, no @The inherited commit (propagated from the caller)
Explicitly versioned foo@DCommit D
External / cross-namespace, no @HEAD (current)

This means a versioned call behaves like a logical snapshot: internal helpers in the same namespace are drawn from the same commit automatically, but cross-namespace dependencies and the standard library use their current values unless explicitly pinned.

Dependency setup

Versioned symbols require the referenced git repository to be cached locally. Declare the dependency in cljrs.edn and run cljrs deps fetch before using versioned symbols:

; cljrs.edn
{:deps
 {my.lib {:git/url "https://github.com/user/my-lib"
           :git/sha "abc1234ef"}}}
cljrs deps fetch my.lib

If the required commit is not cached, clojurust raises a descriptive error rather than attempting a network fetch:

error: dependency 'my.lib' is not cached locally.
       run `cljrs deps fetch` to download it.

Signature verification

When --verify-commit-signatures is passed on the CLI (or :verify-commit-signatures true is set in cljrs.edn), clojurust verifies that every accessed versioned commit carries a valid GPG or SSH signature before executing its code.

Notes

  • Versioned symbols are resolved lazily at call time, not at load time, so the dependency only needs to be cached the first time the code path is actually executed.
  • The version cache is per-GlobalEnv and is keyed on "<ns>/<name>@<commit>", so the same commit of the same namespace is loaded at most once per interpreter session.

Differences from Clojure

This page documents intentional differences, missing features, and behavioural variations between clojurust and Clojure (JVM). The goal is to be a useful reference for porting .cljc code and for understanding what to expect when running Clojure code under clojurust.

No JVM, no Java interop

clojurust runs on Rust, not the JVM. There is no Java class hierarchy, no java.lang.*, and no Java method calls. The . (dot) special form and new have limited implementations:

  • (new Exception "msg") and (Exception. "msg") produce clojurust exception values, not Java objects.
  • (.method obj args...) is not yet implemented. Use protocols or the built-in equivalents instead.

Code that uses (System/nanoTime), (Thread/sleep n), or any other Java static method must use reader conditionals to supply a :rust alternative, or use the clojurust built-ins nanotime and sleep respectively.

Platform key

The reader-conditional platform key is :rust, not :clj. See Reader conditionals.

Missing concurrency features

FeatureStatus
ref / STM (dosync, alter, ref-set, commute, ensure)Not implemented
locking macroNot implemented
monitor-enter / monitor-exitNot implemented

atom, agent, future, promise, delay, and volatile! are fully implemented.

deftype

deftype is not implemented. Use defrecord (which is fully supported) or reify for most cases.

Metadata on collections

Metadata is supported on vars and some values, but not yet propagated through collection operations such as assoc. The with-meta and meta functions work on any value that carries metadata.

Sorted collections

sorted-map and sorted-set are implemented. sorted-map-by and sorted-set-by (custom comparators) are not yet implemented.

Hierarchies

make-hierarchy, ancestors, descendants, and parents have stub implementations. derive, underive, and a full isa? hierarchy are not yet implemented. defmulti / defmethod dispatch works but does not consult a custom hierarchy.

amap and areduce

These macros are registered as stubs but not fully implemented.

clojure.pprint

Not implemented.

clojure.zip

Stub — the namespace exists but most functions are not yet implemented.

Numeric tower

The numeric tower (Long → BigInt → Ratio → BigDecimal → Double) follows Clojure conventions. A few differences to be aware of:

  • Integer overflow in +, -, * automatically promotes to BigInt (same as Clojure’s checked arithmetic). The promoting variants +', -', *' are also available.
  • (/ 1 3) returns a Ratio (1/3), not a Double, same as Clojure.
  • BigDecimal precision is controlled by with-precision (the Clojure macro) or the lower-level push-precision! / pop-precision! built-ins.

*clojure-version* / *cljrs-version*

These vars are not yet defined. clojure-version as a function returns a map describing the current runtime.

with-open and close

clojurust provides RAII-style resource management via with-open (a macro) and close (a built-in function). These follow the same protocol as Clojure’s with-open; any value that implements the Resource protocol can be used.

Source file namespace mapping

The namespace→file mapping converts . to / and - to _, the same as Clojure:

myapp.core    →  myapp/core.cljrs  (or .cljc)
my-app.utils  →  my_app/utils.cljrs

Standard library

The following clojure.* namespaces are available: clojure.string, clojure.set, clojure.test, clojure.walk, clojure.edn, clojure.data.

clojure.zip and clojure.pprint exist as stubs. clojure.spec.alpha, clojure.core.async, and clojure.core.match are not available.

New built-in functions

clojurust adds a small number of built-in functions that have no direct equivalent in standard Clojure. Most exist because Clojure code would normally reach these capabilities through Java interop, which is not available in clojurust.


System / time

(sleep ms)

Pause the current thread for ms milliseconds.

(sleep 100)   ; sleep 100 ms

Clojure equivalent: (Thread/sleep ms).


(nanotime)

Return the number of nanoseconds since the Unix epoch as a Long.

(let [start (nanotime)
      _     (do-work)
      end   (nanotime)]
  (println "elapsed ns:" (- end start)))

Clojure equivalent: (System/nanoTime) (note: Clojure’s version is relative to an arbitrary origin; clojurust’s is Unix epoch-relative).


String utilities

(char-code c)

Return the Unicode code point of character c as a Long.

(char-code \A)    ; => 65
(char-code \λ)    ; => 955

Clojure equivalent: (int c).


(char-at s i)

Return the character at index i in string s.

(char-at "hello" 1)   ; => \e

Clojure equivalent: (.charAt s i).


(string->list s)

Convert string s to a list of its characters.

(string->list "abc")   ; => (\a \b \c)

Clojure equivalent: (seq s) (returns a seq, not a list, but behaves the same in most contexts).


(number->string n)

Convert number n to its string representation.

(number->string 42)     ; => "42"
(number->string 3.14)   ; => "3.14"

Clojure equivalent: (str n).


(string->number s) / (string->number s base)

Parse string s as a number, returning nil if the string is not a valid number. The optional base argument specifies the radix (default 10).

(string->number "42")      ; => 42
(string->number "3.14")    ; => 3.14
(string->number "ff" 16)   ; => 255
(string->number "nope")    ; => nil

Clojure equivalent: no single equivalent; typically (Integer/parseInt s), (Double/parseDouble s), or a try/catch around those.


BigDecimal precision

(push-precision! n) / (push-precision! n mode)

Push a BigDecimal precision context onto the thread-local precision stack. Subsequent BigDecimal operations are rounded to n significant digits using mode (default HALF_UP).

Available rounding modes: CEILING, FLOOR, HALF_UP, HALF_DOWN, HALF_EVEN, UP, DOWN, UNNECESSARY.

(push-precision! 4)
(/ 1M 3M)    ; => 0.3333 (4 significant digits)
(pop-precision!)

This is the lower-level mechanism underlying the with-precision macro (which is preferred in normal code). Use push-precision! / pop-precision! only when you need to manage the precision stack manually across multiple calls.

Clojure equivalent: with-precision (macro).


(pop-precision!)

Pop the most recently pushed BigDecimal precision context.


Persistent queue

(queue) / (queue capacity)

Create a new empty persistent queue. The optional capacity argument is a size hint for the initial allocation.

(def q (queue))
(def q2 (conj q :a :b :c))
(peek q2)   ; => :a
(pop  q2)   ; => queue with [:b :c]

Clojure equivalent: clojure.lang.PersistentQueue/EMPTY (a Java static field).


Mutable ArrayList

These functions provide a mutable, GC-managed resizable array backed by a Rust Vec. They are intended for performance-sensitive code that builds up a collection before converting it to an immutable value, or for interoperating with Rust code that expects a mutable sequence.

An ArrayList value is a NativeObject; it is not a Clojure collection and cannot be used with seq, conj, map, etc. directly. Convert it with array-list-to-array first.

(array-list) / (array-list capacity)

Create a new empty ArrayList. With a Long argument, pre-allocates storage for capacity elements.

(def al (array-list 16))

(array-list-push al v)

Append value v to the end of al. Returns al (mutates in place).

(array-list-push al :x)
(array-list-push al :y)

(array-list-remove al i)

Remove and return the element at index i. Later elements shift left.

(array-list-remove al 0)   ; removes and returns first element

(array-list-length al)

Return the number of elements in al as a Long.

(array-list-length al)   ; => 2

(array-list-to-array al)

Convert al to an immutable object array (Value::ObjectArray). The ArrayList is unaffected.

(def arr (array-list-to-array al))
(alength arr)   ; => 2

(array-list-clear al)

Remove all elements from al. Returns al.

(array-list-clear al)

Rust interop

(native-object? x)

Return true if x is a NativeObject (a Rust value wrapped for use in clojurust), false otherwise.

(native-object? (array-list))   ; => true
(native-object? [1 2 3])        ; => false

(native-type x)

Return the type-tag string of NativeObject x, or nil if x is not a NativeObject.

(native-type (array-list))   ; => "ArrayList"
(native-type 42)             ; => nil

The type tag is set by the Rust code that implements the NativeObject trait and is the primary mechanism for dispatching on native types from clojurust code.