cljrs-stdlib
Built-in standard library namespaces for clojurust, distributed as embedded source + native Rust helpers.
Status
Phase 8-ext. Provides clojure.string, clojure.set, and clojure.test as
lazily-loaded built-ins; no filesystem dependency at runtime.
Purpose
Clojurust has no classpath or JAR mechanism. This crate solves the distribution
problem by embedding .cljrs source files via include_str! and registering
them in GlobalEnv::builtin_sources so that (require '[clojure.string :as str])
works out of the box in any binary that calls cljrs_stdlib::standard_env().
File layout
src/
lib.rs Public API: register(), standard_env(), standard_env_with_paths()
string.rs Native Rust implementations for clojure.string
set.rs Native Rust implementations for clojure.set
clojure/
string.cljrs Clojure source for clojure.string (ns decl; natives pre-registered)
set.cljrs Clojure source for clojure.set (ns decl; natives pre-registered)
test.cljrs Pure Clojure implementation of clojure.test
spec/
alpha.cljrs Pure Clojure implementation of clojure.spec.alpha (core spec engine)
test/
alpha.cljrs Pure Clojure implementation of clojure.spec.test.alpha (instrument/unstrument)
gen/
alpha.cljrs clojure.spec.gen.alpha stub — every fn throws (no generator engine)
build.rs Pre-lowers clojure.core to optimized IR (gated on the
`prebuild-ir` feature) — runs the ANF lowerer *and*
the escape-analysis/region-allocation optimize pass,
so the resulting bundle includes the RegionStart/
RegionAlloc instructions consumed by the IR
interpreter. Output: `$OUT_DIR/core_ir.bin`.
Public API
Entry points
/// Register all built-in stdlib namespaces into an existing GlobalEnv.
;
/// Create a GlobalEnv with bootstrap + stdlib registered (lazy loading).
;
/// Like standard_env() but also sets user source paths for require.
;
Namespaces provided
| Namespace | Implementation | Notes |
|---|---|---|
clojure.string |
string.rs + clojure/string.cljrs |
Native Rust, loaded lazily |
clojure.set |
set.rs + clojure/set.cljrs |
Native Rust, loaded lazily |
clojure.test |
clojure/test.cljrs |
Pure Clojure, loaded lazily |
clojure.spec.alpha |
clojure/spec/alpha.cljrs |
Pure Clojure, loaded lazily |
clojure.spec.test.alpha |
clojure/spec/test/alpha.cljrs |
Pure Clojure, loaded lazily |
clojure.spec.gen.alpha |
clojure/spec/gen/alpha.cljrs |
Pure Clojure, loaded lazily; every fn throws (no generator engine) |
clojure.string functions
upper-case, lower-case, capitalize, trim, triml, trimr,
trim-newline, blank?, starts-with?, ends-with?, includes?,
replace, replace-first, split, split-lines, join,
index-of, last-index-of
replace and replace-first accept either a string or a regex pattern
(#"...") as the match argument. When the match is a pattern, replace
replaces all occurrences and replace-first replaces only the first.
clojure.set functions
union, intersection, difference, subset?, superset?,
select, map-invert
clojure.spec.alpha functions and macros
A from-scratch, spec-compatible-in-spirit implementation of the core spec
engine: predicate/set/keyword specs, and/or composition, keys/merge,
the derivative-based regex engine (cat/alt/*/+/?/&), collection
specs, and fn-specs (fdef/fspec).
Macros: def, spec, and, or, keys, merge, cat, alt, *, +,
?, &, every, coll-of, every-kv, map-of, tuple, nilable,
multi-spec, conformer, nonconforming, fspec, fdef, assert
Functions: registry, get-spec, invalid, invalid?, spec-name,
spec?, conform, unform, valid?, form, describe, explain-data,
explain, explain-str, explain-out, regex?, int-in, double-in,
inst-in (throws — see deviations), check-asserts?, check-asserts,
with-gen, gen, exercise, exercise-fn (the last three throw — see
deviations)
Deviations from JVM clojure.spec.alpha
- No generators:
s/gen,s/exercise,s/exercise-fn, andstest/check/stest/check-fnall throw a clearex-infoinstead of running test.check.s/with-genstores the generator fn without ever invoking it. s/formands/describeshow forms exactly as written (unqualified) — they do not auto-qualify bare symbols toclojure.corethe way upstream does.multi-specunform re-dispatches by calling the multimethod on the conformed value rather than applying JVM spec'sretagmechanism.check-assertstakes effect immediately (read at assert-expansion time), not just at compile time as on the JVM.inst-inalways throws — this runtime has noinst?/date value type to bound.- Users must
:requirethe namespace with an alias (:as s, the universal convention anyway).:refering names likeand,or, ordefcollides with clojurust's special forms, and:refer-clojure :excludeis a no-op in this runtime, so it cannot be used to work around the collision.
clojure.spec.test.alpha functions and macros
Macros: with-instrument-disabled
Functions: instrument, unstrument, instrumentable-syms, check (throws
— see deviations), check-fn (throws — see deviations)
instrument wraps a var's root fn so every call conforms its argument list
against the fn's fdef'd :args spec before delegating to the original fn;
only :args is checked (never :ret/:fn, matching upstream). unstrument
restores the original fn. Both are idempotent.
clojure.spec.gen.alpha functions
generate, sample, gen-for-pred, choose, such-that, fmap, one-of,
return, elements, int, string, keyword, boolean, double,
simple-type, any
This namespace has no generator engine (no test.check port): every function
throws a clear ex-info explaining that generators are not implemented. It
exists purely so that idiomatic specs which (:require [clojure.spec.gen.alpha :as gen]) load cleanly. As in upstream, several names (int, string,
keyword, boolean, double) intentionally shadow clojure.core.
Dependency notes
cljrs-stdlibdepends oncljrs-eval(forGlobalEnv,standard_env_minimal)cljrs-evaldoes not depend oncljrs-stdlib(no circular dep)- The
cljrsbinary depends on both; usecljrs_stdlib::standard_env()instead ofcljrs_eval::standard_env()so that stdlib namespaces are available