Skip to content

Add a Rust crate to an Incan program

This tutorial puts Rust's regex crate behind a small Incan boundary. An explicit Oven bake prepares the locked project extension; normal Incan commands then reuse it without invoking Cargo on the consumer path.

Step 1: Import a versioned crate

Create main.incn:

from rust::regex @ "1" import Regex  # (1)
  1. rust:: selects Rust interop; @ "1" pins the compatible crate major version for this single-file program.

The rust:: prefix identifies a Rust dependency. The inline version annotation is convenient for a single-file program.

Step 2: Wrap the Rust-facing API

from rust::regex @ "1" import Regex

def contains_number(pattern: Regex, input: str) -> bool:
    return pattern.is_match(input)

def main() -> None:
    pattern = Regex.new("\\d+").unwrap()  # (1)
    for sample in ["invoice-42", "invoice-pending"]:
        println(f"{sample}: {contains_number(pattern, sample)}")  # (2)
  1. The constructor is fallible. unwrap() is acceptable here only because "\\d+" is a fixed, reviewed source literal; the warning below describes the input-driven case. Compiling it once keeps that cost visible.
  2. The prepared regex is reused by the predicate instead of being recompiled for every item.

Only this helper needs to know the Rust crate's constructor and methods. Callers get an ordinary Incan function.

About unwrap()

The pattern is a fixed source literal in this tutorial. If the expression comes from a user, configuration file, or network input, keep Regex.new(...) fallible and return or match its error instead of unwrapping it.

Step 3: Move the dependency into the manifest

main() now owns the one-time Rust-facing construction, while contains_number(...) remains a small ordinary predicate over a prepared value.

For a project, move the version into incan.toml and make the source import versionless:

[rust-dependencies]
regex = "1"
from rust::regex import Regex

The manifest is now the single source of truth for the project dependency. Do not retain the inline @ "1" annotation after adding it.

Step 4: Lock, bake, and run

The complete repository example includes that manifest. Prepare its dependency closure explicitly, then use the normal command path:

cd examples/rust_interop_regex
incan lock
incan oven bake --project . --format json
incan run --locked

incan lock writes the reproducible dependency graph. The explicit bake may invoke the bounded compatibility publisher once and seals a project-extension Loaf over the exact full-standard-library base. incan run --locked then selects that immutable closure and rejects drift; it never invokes Cargo as a hidden fallback. Commit incan.lock so CI and collaborators resolve the same graph.

You contained the Rust-facing calls in one helper, made the dependency reproducible, baked the project extension explicitly, and ran the resulting native program through the normal Incan command path.

Continue