rustler_match_spec
Reusable Erlang-style match specifications for Rustler native event streams.
This crate is for Rustler NIFs that produce many small structured facts from native code, such as parser events, CSS dependencies, trace events, or resource metadata. Instead of returning a whole native data structure to Elixir and walking it on the BEAM, the NIF can expose a stream of tuple-like events and let Elixir select the facts it wants.
The Elixir side builds a match spec. The Rust side decodes it into a Selector and applies it to native events.
Why
A common Rustler pattern is:
- parse or analyze something in Rust,
- serialize a large AST or result tree to Elixir,
- walk that structure in Elixir to find a few pieces of information.
rustler_match_spec supports a narrower shape:
- parse or analyze something in Rust,
- emit compact native events,
- filter/project those events with an Elixir-provided selector,
- return only the selected results.
This is useful when the parser is already native and Elixir only needs facts such as import specifiers, asset URLs, source ranges, or dependency records.
Elixir usage
The companion Elixir package exposes a small DSL:
import RustlerMatchSpec
spec =
match_spec do
{:import, source, start, finish} when is_binary(source) ->
{source, start, finish}
end
selector = RustlerMatchSpec.compile(spec)
RustlerMatchSpec.select(events, selector)
The macro compiles to plain match-spec-shaped data, so selector terms can also be passed into your own NIF APIs.
Rust integration
Native event types implement MatchEvent:
use ;
use ;
#
Tuple patterns match tag() plus positional fields. For a pattern like:
{:import, source, start, finish}
tag() is matched against :import, and positional_field(1), positional_field(2), and positional_field(3) provide the remaining tuple elements.
API surface
The main Rust types are:
Selector— decoded/compiled match-spec plan.MatchEvent— trait implemented by native event types.ValueRef— borrowed value returned by event fields.
The crate also includes NIF helpers used by the Elixir package:
compile/1select/2
Real use
The crate was originally extracted for the Elixir Volt toolchain. OXC and Vize use it to implement parser-backed selectors for JavaScript and CSS facts. Volt then uses those selectors to avoid repeated parse + AST-walk passes for imports, assets, workers, glob imports, and environment references.
On a Monaco Editor build in Exograph, this helped reduce OXC parse calls from 8043 to 3236 and improved the warm build from about 17.5s to about 14.3s.
License
MIT