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

Welcome to SnapCrab

SnapCrab is an experimental Rust interpreter designed to accelerate local development by executing Rust code without the overhead of compilation and linking.

Traditional Rust development requires a full compilation and linking cycle for every code change, which can slow down the development process. SnapCrab aims to solve this by interpreting Rust code directly, enabling rapid iteration during development.

Key Features

  • Fast execution: Skip compilation and linking overhead
  • Test-focused: Execute unit tests (#[test] functions) instantly
  • Development-oriented: Optimized for quick feedback during coding
  • Linux x86-64 target: Initial platform support

Current Status

SnapCrab is in early development, starting with a limited subset of Rust syntax to evaluate project feasibility. The initial focus is on small binary programs and basic language constructs, with plans to expand support for external dependencies and broader Rust features.

Getting Started

This documentation will guide you through using SnapCrab for faster Rust development workflows.

Beyond providing a fast interpreter, SnapCrab serves as a tool to identify gaps in the rustc_public APIs and as a practical example demonstrating how to use these APIs for building Rust tooling. The project acts as a testbed for exploring compiler interface improvements.

Architecture

SnapCrab will consist of two main components that work together to provide fast Rust code interpretation: the interpreter and the cargo driver.

Interpreter

The interpreter will be a rustc wrapper that leverages rustc_public to interpret the target crate’s MIR (Mid-level Intermediate Representation).

Key responsibilities:

  • Parse and analyze Rust source code using rustc’s frontend
  • Generate MIR for the target crate
  • Execute MIR instructions directly without code generation
  • Provide runtime environment for interpreted execution
  • Handle function calls, control flow, and memory operations
  • Dynamically load libraries and invoke native code for cross-language interoperability
  • Support potential JIT compilation strategies for performance optimization

By operating at the MIR level, the interpreter will execute Rust code without the overhead of LLVM code generation and linking, significantly reducing iteration time during development. The ability to dynamically load libraries will enable seamless integration with existing native code, while the foundation for JIT compilation will allow for performance improvements in hot code paths.

Cargo Driver

The cargo driver will handle dependency management and compilation coordination. It will compile the crate and its dependencies, then trigger the interpreter for the target code.

Key responsibilities:

  • Compile external dependencies using standard rustc
  • Coordinate between compiled dependencies and interpreted target code
  • Manage the build process and dependency resolution
  • Interface between cargo’s build system and the interpreter
  • Handle mixed compilation scenarios (compiled deps + interpreted target)

This approach will allow SnapCrab to leverage the existing Rust ecosystem while providing fast execution for the code under development.

Memory Tracking and Safety

The main goal of the interpreter architecture is speed. With that in mind, UB (Undefined Behavior) checking is limited and done in a best effort approach, mostly to avoid the interpreter execution from triggering UB.

Memory access is tracked by recording allocated memory regions with their addresses and sizes. However, there’s no provenance or ownership tracking - the system focuses on bounds checking rather than Rust’s ownership semantics. All allocated memories are initialized to zero to avoid reading uninitialized memory. Each stack frame is tracked as a single allocation containing all local variables in a contiguous byte array.

This approach prioritizes execution speed while providing basic memory safety guarantees. To check for UB, we recommend using MIRI.

Getting Started

This guide will help you get started with SnapCrab for faster Rust development workflows.

Installation

SnapCrab is currently in early development. To build from source:

git clone <repository-url>
cd snapcrab
cargo build --release

Usage

SnapCrab is designed to execute small Rust programs and unit tests without compilation overhead.

Running the Main Function

Execute the main function of a Rust source file:

snapcrab <file.rs>

Running a Specific Function

Execute a specific function by name (requires fully qualified name):

snapcrab --start-fn <function_name> <file.rs>

Limitations

Current limitations in the early development phase:

  • Limited subset of Rust syntax supported
  • Small binary programs only / no cargo support yet
  • Basic language constructs
  • Linux x86-64 target only

Future expansion will include external dependencies and broader Rust feature support.

Developer Guide

Welcome to SnapCrab development! We appreciate your interest in our project. This guide will help you get started contributing to the project.

Whether you’re fixing a bug, adding a feature, or improving documentation, this guide covers the development practices and tools that will help you contribute effectively.

Before making code changes, we recommend creating an issue if one doesn’t exist yet, and commenting that you would like to work on it. This helps avoid conflicting contributions and allows for discussion about the approach.

Git Usage

For simplicity, we try to keep the history of main linear. Ideally, try to keep each commit small, and make sure it at least compiles.

Commit Message Format

We try to keep our messages coherent with widely adopted conventions:

  • Title: Maximum 50 characters
  • Body: Maximum 80 characters per line
  • Types: The title should include the type of change introduced by the commit. Follow conventional commit format.

Git Hooks

We recommend Git hooks to enforce code quality and commit message standards.

Pre-commit Hook

The pre-commit hook runs code formatting and linting checks:

#!/bin/bash

echo "Running pre-commit checks..."

# Run cargo check
if ! cargo check --quiet; then
    echo "Error: Code does not compile. Fix compilation errors before committing."
    exit 1
fi

# Run cargo fmt check
if ! cargo fmt --check; then
    echo "Error: Code is not formatted. Run 'cargo fmt' to fix."
    exit 1
fi

# Run cargo clippy
if ! cargo clippy -- -D warnings; then
    echo "Error: Clippy found issues. Fix them before committing."
    exit 1
fi

echo "Pre-commit checks passed!"
exit 0

Save this as .git/hooks/pre-commit and make it executable:

chmod +x .git/hooks/pre-commit

Commit Message Hook

The commit message hook enforces conventional commit format and character limits:

#!/bin/bash

commit_file="$1"
commit_msg=$(cat "$commit_file")

# Extract title (first line) and body (rest)
title=$(echo "$commit_msg" | head -n1)
body=$(echo "$commit_msg" | tail -n +3)

error_found=false

# Check title length
if [ ${#title} -gt 50 ]; then
    echo "Error: Commit title exceeds 50 characters (${#title})"
    error_found=true
fi

# Check conventional commit format
if ! echo "$title" | grep -qE '^(feat|fix|docs|style|refactor|test|chore|perf|ci|build|revert)(\(.+\))?: .+'; then
    echo "Error: Title must follow conventional commit format"
    echo "Format: type(scope): description"
    echo "Types: feat, fix, docs, style, refactor, test, chore, perf, ci, build, revert"
    error_found=true
fi

# Check body line lengths
while IFS= read -r line; do
    if [ ${#line} -gt 80 ]; then
        echo "Error: Body line exceeds 80 characters (${#line})"
        error_found=true
    fi
done <<< "$body"

if [ "$error_found" = true ]; then
    echo ""
    echo "Rejected commit message:"
    echo "========================"
    echo "$commit_msg"
    exit 1
fi

exit 0

Save this as .git/hooks/commit-msg and make it executable:

chmod +x .git/hooks/commit-msg

Next Steps

This is a loose TODO list with things we’re planning to add next. This is not meant to be a compreheensive list. A lot of the coverage we will add as we try more complex examples.

  • Reference handling

  • Heap allocation

  • Static objects

  • Drop semantics

  • ADTs

  • Intrinsics

  • DST

  • Crate loading

  • FFI support

  • Standard library

RustC Public

Here is a list of things that we can improve in rustc_public:

  1. Add PlaceRef. Make it more efficient to process Place.
    • Once we do this, we can remove place creation in the interpreter
  2. Add a way to retrieve all mono items
  3. Add a way to retrieve source for a span so we can use annotate_snippets.