Status: reviewable baseline
Last updated: 2026-03-09
This document defines the current honest Tonic Core Stdlib for real programs.
The goal is not to clone Elixir's full standard library. The goal is to ship a small, believable, Elixir-shaped subset whose exposed surface, implementation boundary, docs, and tests all agree.
Tonic should be understood as:
- Elixir-inspired syntax and code shape
- a non-BEAM runtime
- an interpreted/native language with a host-backed optional stdlib
That means Tonic should:
- borrow Elixir module names and function shapes where practical
- avoid claiming BEAM/OTP semantics it does not implement
- prefer explicit divergence over implied parity
- advertise only surfaces that are actually supported end to end
Optional stdlib injection now works in both project mode and single-file mode.
Both paths share the same inject_optional_stdlib logic in src/manifest.rs:
tonic run <project-dir>lazy-loads optional stdlib modules via project manifest loadingtonic run file.tnnow also analyzes the source for stdlib references and injects needed modules
The stdlib contract is module-dependent but no longer execution-mode-dependent.
This baseline is grounded in:
src/manifest.rssrc/interop.rssrc/interop/system.rssrc/interop/string_mod.rssrc/interop/path_mod.rssrc/interop/io_mod.rssrc/interop/map_mod.rssrc/interop/enum_mod.rssrc/c_backend/stubs.rstests/run_lazy_stdlib_loading_smoke.rs- native compiled runtime smoke coverage for Map stdlib
- native compiled runtime smoke coverage for IO stdlib
examples/apps/stdlib_showcase
The original profile work was driven by tonic-sitegen-stress, but the current baseline is broader than that one workload. The support bar is now: exposed surface + interpreter behavior + native behavior + regression coverage + docs that match reality.
A stdlib surface belongs in the current Tonic Core Stdlib only if all of the following are true:
- The module is intentionally exposed by
src/manifest.rs. - Interpreter behavior exists and is intentional.
- Native compiled behavior exists for every public host-backed helper that the module exposes.
- Regression coverage exists for the supported behavior.
- Docs and examples match the real boundary.
If any of those are missing, the surface may still be a future candidate, but it is not part of the supported core profile.
| Label | Meaning |
|---|---|
| Core-supported | Publicly exposed in project mode, intentional, covered, and aligned across interpreter/native behavior |
| Deferred | Intentionally not part of the current supported project-mode stdlib surface |
At the manifest-injection level, the current optional project-mode stdlib surface is exactly:
SystemStringPathIOListMapEnum
These modules lazy-load in project mode when referenced.
The current support boundary is intentionally split between pure Tonic code and host-backed primitives.
System remains host-backed. It is the practical boundary for:
- filesystem operations
- process execution
- environment access
- CLI input/output helpers
- HTTP client/server helpers
- selected crypto helpers
Representative supported surface includes:
System.path_exists/1System.list_files_recursive/1System.remove_tree/1System.ensure_dir/1System.read_text/1System.write_text/2System.read_stdin/0System.run/1System.argv/0System.cwd/0System.env/1System.which/1
String remains host-backed because the current text contract and UTF-8-sensitive behavior are runtime concerns, not a good target for a forced pure-Tonic rewrite.
Representative supported surface includes:
String.split/2String.trim/1String.trim_leading/1String.trim_trailing/1String.starts_with/2String.ends_with/2String.contains/2String.slice/3String.to_integer/1String.to_charlist/1
Path remains host-backed. It is small, useful, and already parity-backed.
Current public surface:
Path.join/2Path.dirname/1Path.basename/1Path.extname/1Path.expand/1Path.relative_to/2
IO is public again, but it intentionally remains host-backed.
Current public surface:
IO.puts/1IO.inspect/1IO.gets/1IO.ansi_red/1IO.ansi_green/1IO.ansi_yellow/1IO.ansi_blue/1IO.ansi_reset/0
Reason: stdin/stdout/stderr and ANSI behavior are runtime primitives, not library code.
Map is public again, but only for the bounded surface Tonic can honestly support today.
Current public surface:
Map.keys/1Map.values/1Map.merge/2Map.drop/2Map.take/2Map.get/3Map.put/3Map.delete/2
Current non-goals:
Map.has_key?/2is still deferred until the parser/public surface can expose?-suffixed APIs cleanly.Map.filter/2andMap.reject/2are not advertised because the current public language/runtime story is not yet good enough to claim them honestly.
List is public and implemented directly in injected Tonic source.
Current public surface:
List.first/1List.last/1List.wrap/1List.flatten/1List.zip/2List.unzip/1
These are pure structural transforms and are a better fit in Tonic than in Rust host glue.
Enum is public again, but it has an intentional split.
Pure Tonic helpers:
Enum.count/1Enum.sum/1Enum.reverse/1Enum.take/2Enum.drop/2Enum.chunk_every/2Enum.unique/1Enum.into/2for list and bounded map collectables
Remaining host-backed helpers:
Enum.join/2Enum.sort/1
Reason: the pure transforms are cleanly expressible in Tonic today, while join and sort still rely on runtime-side stringification/comparison behavior.
| Module/surface | Profile status | Implementation shape |
|---|---|---|
System |
Core-supported | Host-backed |
String |
Core-supported | Host-backed |
Path |
Core-supported | Host-backed |
IO |
Core-supported | Host-backed |
List |
Core-supported | Pure Tonic |
Map |
Core-supported | Bounded host-backed surface |
Enum |
Core-supported | Mixed pure/host split |
URI / Keyword / Integer / Float / Tuple / OptionParser / Regex / Stream |
Deferred | Not part of the current public optional stdlib surface |
A stdlib function should be described as supported only when all of the following are true:
- Project-mode exposure exists in
src/manifest.rs. - Interpreter support exists for the intended argument and error contract.
- Native compiled support exists for the same contract when the function is host-backed.
- Any known divergence is documented.
- Regression coverage exists in repo tests.
- Advertising matches reality across docs, examples, and module lists.
A function should not be advertised as supported when any of these are true:
- only the interpreter works
- only the native path works
- the wrapper exists but native dispatch does not
- the module injects but the docs still describe it as deferred
- the docs describe behavior that no regression test covers
Tonic should be Elixir-shaped where practical, but this profile intentionally does not promise BEAM/OTP semantics.
Tonic does not claim support for:
GenServerSupervisorTaskAgentProcessNode- Erlang mailbox/process/distribution semantics
- implicit OTP application/runtime behavior
Tonic also still has an explicit text/runtime divergence:
- runtime text is still binary-shaped rather than a parser-ready byte/list type
- parser-style byte decomposition is not the current runtime text contract
- parser-heavy code should still lean on the supported
String.*helpers or explicit workload-specific helpers
See text-binary-parser-contract.md.
For a small runnable example of the current project-mode surface, see:
examples/apps/stdlib_showcase
It demonstrates List, Enum, Map, and non-interactive IO.inspect/1 together under the same project-mode lazy-loading contract the docs describe.
The current honest Tonic Core Stdlib profile is:
- Core-supported host-backed modules:
System,String,Path,IO - Core-supported pure collection module:
List - Core-supported bounded collection modules:
MapandEnum, with the documented host/pure split - Deferred: broader Elixir-shaped utility modules until demand, runtime support, and parity justify them
- Still caveated: optional stdlib injection remains project-mode-only
That is a much stronger claim than the older System/String/Path-only baseline, but it is still intentionally narrower than “Elixir stdlib compatibility”. The point is not breadth. The point is a supported surface users can actually rely on.