# RustScript
[](https://crates.io/crates/run-rs)
[](https://github.com/VladasZ/rustscript/actions/workflows/ci.yml)
[](https://github.com/marketplace/actions/rustscript-action)
[](#licence)
[](https://github.com/VladasZ/rustscript/releases/latest)
[](https://github.com/VladasZ/rustscript/releases/latest)
[](https://github.com/VladasZ/rustscript/releases/latest)
Run helper and automation scripts in Rust without waiting for a full compile.
RustScript interprets a practical subset of the language. `rust check`
validates the same files with rustc.
## Install
Install the [`run-rs`](https://crates.io/crates/run-rs) package from crates.io:
```sh
cargo install run-rs
```
This installs a binary named `rust`.
## First script
```rust
#!/usr/bin/env rust
use std::fs;
fn main() -> anyhow::Result<()> {
let text = fs::read_to_string("notes.txt")?;
println!("{} lines", text.lines().count());
Ok(())
}
```
Make the file executable and run it directly:
```sh
chmod +x notes.rs
./notes.rs
```
## Usage
```text
rust FILE.rs interpret the script
rust run FILE.rs same as above
rust check FILE.rs validate without running
rust build FILE.rs compile, cache, and run a native binary
rust clean clear cached checks and builds
rust update install the newest RustScript release
rust --version show version and build information
```
Arguments after the file are passed to the script. The first argument `cmp` is
reserved as a shorthand for compiled mode:
```sh
rust tool.rs one two
rust tool.rs cmp one two
```
The shebang is valid Rust, so the same file can still be compiled or checked by
Cargo. Symlinks to scripts work too, including extensionless command names.
## How it works
- `rust FILE.rs` parses the source with
[`syn`](https://github.com/dtolnay/syn), compiles it to bytecode, and runs it
on a register VM. It does not invoke Cargo or a type checker.
- `rust check FILE.rs` creates a small Cargo project and runs `cargo check`.
It then inspects every compiled branch for method calls the interpreter does
not implement. Results are cached by source hash.
- `rust build FILE.rs` asks Cargo for a native binary, caches it, and runs it.
Use it for CPU-heavy scripts that justify the initial build.
rustc remains responsible for type, ownership, borrowing, and visibility
errors. The interpreter does not implement a second Rust type system.
## Supported Rust
Supported language features include:
- functions, recursion, closures, methods, associated functions, and aliases
- structs, tuple structs, enums, patterns, guards, `if let`, and `let else`
- loops, ranges, arithmetic, comparison, casts, and bitwise operations
- `Vec`, strings, maps, sets, `Option`, `Result`, and `?`
- iterators including `map`, `filter`, `fold`, `find`, sorting, and predicates
- formatting, named arguments, width, precision, and common macros
- modules, imports, re-exports, constants, statics, and local path crates
- `#[tokio::main]`, spawned tasks, joins, yielding, timers, and async HTTP
The standard-library bridge covers files, directories, paths, stdin and stdout,
buffered I/O, processes, TCP sockets, environment variables, arguments, time,
and collections.
The following crates have native interpreter bridges:
- [`anyhow`](https://github.com/dtolnay/anyhow),
[`serde`](https://serde.rs), and
[`serde_json`](https://github.com/serde-rs/json)
- [`reqwest`](https://github.com/seanmonstar/reqwest),
[`regex`](https://github.com/rust-lang/regex),
[`jsonwebtoken`](https://github.com/Keats/jsonwebtoken), and
[`tokio`](https://tokio.rs)
- [`chrono`](https://github.com/chronotope/chrono),
[`rand`](https://github.com/rust-random/rand),
[`which`](https://github.com/harshadgavali/which-rs),
[`glob`](https://github.com/rust-lang/glob), and
[`dirs`](https://github.com/dirs-dev/dirs-rs)
- [`toml`](https://github.com/toml-rs/toml),
[`serde_yaml`](https://github.com/dtolnay/serde-yaml),
[`base64`](https://github.com/marshallpierce/base64),
[`hex`](https://github.com/KokaKiwi/rust-hex), and
[`colored`](https://github.com/colored-rs/colored)
- [`ctrlc`](https://github.com/Detegr/rust-ctrlc) and
[`tempfile`](https://github.com/Stebalien/tempfile)
Windows builds also bridge
[`winreg`](https://github.com/gentoo90/winreg-rs),
[`windows-service`](https://github.com/mullvad/windows-service-rs), and
[`wmi`](https://github.com/ohadravid/wmi-rs).
See the programs under `crates/examples/examples` for working examples of the
language, standard library, and crate bridges.
## Modules and local crates
Normal module layouts work: `mod name;` loads `name.rs` or `name/mod.rs`, and
modules can nest to any depth. Imports support `crate::`, `self::`, `super::`,
renames, groups, and re-export chains.
A script inside a Cargo project can use local library crates declared as path
dependencies in the nearest `Cargo.toml`. Both the interpreter and `rust check`
load the same source tree.
See [Writing multifile scripts](docs/multifile.md) for layout rules, a complete
example, and the unsupported module forms.
## Current limitations
`cargo check` proves that a program is valid Rust, not that every operation has
an interpreter bridge. `rust check` adds that coverage pass.
- Crates without a native bridge stop with an `unsupported crate` error.
- Coverage currently checks methods, not path calls such as
`std::process::exit`.
- `#[path]` module declarations and glob imports from script modules are not
supported.
- `std::thread` is not supported; use Tokio tasks for parallel work.
- `static mut` is rejected. Plain statics behave like constants.
- Lifetimes and generics are accepted but carry no runtime meaning.
- Serde container attributes such as `rename_all` and `default` are not yet
implemented by the reflection bridge.
## Caching
Checks, compiled binaries, and shared Cargo dependencies live under
`~/.cache/rustscript`. Interpreted runs do not touch the cache. `rust clean`
removes it.
## GitHub Actions
The repository is also a GitHub Action:
```yaml
- uses: VladasZ/rustscript@v0.1
with:
script: tools/release.rs
args: --dry-run
```
The Action downloads a checksum-verified prebuilt binary, so setup takes
seconds instead of compiling the crate. It supports Linux, macOS, and Windows
on x86_64 and arm64. See the [GitHub Actions guide](docs/github-actions.md) for
inputs, outputs, version selection, and pinning.
## Development
Install the current checkout when testing unpublished changes:
```sh
cargo install --path crates/rustscript
```
Run the repository checks:
```sh
cargo fmt --all -- --check
cargo clippy --workspace --all-targets -- -D warnings
cargo test --workspace
```
The equivalence tests run the same examples through rustc and the interpreter
and compare their output byte for byte. The multifile conformance test does the
same for a deep module tree.
## Benchmarks
The benchmark suite compares RustScript with native Rust, Node, and Python on
equivalent programs. It records wall time, compute time, peak memory, raw
samples, and build provenance.
See the [benchmark guide](bench/README.md) for methodology and results, and the
[profiling guide](docs/profiling.md) for finding interpreter hot spots.
## Releases
RustScript is still 0.x, so minor versions may contain breaking changes. Exact
tags such as `v0.1.5` never move; the `v0.1` tag follows the newest patch in
that line. Pin an exact tag when a workflow must not change.
`rust update` finds the newest full GitHub release and installs it with Cargo.
Prereleases and moving minor tags are not update targets.
## Licence
Dual licensed under either [MIT](LICENSE-MIT) or
[Apache-2.0](LICENSE-APACHE), at your option.