Valid-Elixir macro frontend for generating RustQ Rust fragments.
defrust captures a normal Elixir function-shaped body plus its preceding
@spec, lowers that quoted Elixir AST to Rust, and exposes generated Rust
items through __rustq_items__/0 and __rustq_source__/0.
defrustmod is for RustQ-owned Rust module structure. Prefer its block form
when RustQ is generating the Rust module and the nested functions. Do not use
it as a hand-written alias for Rust modules/types that are owned by another
generator or crate; those callers should derive/render their Rust paths at
their own codegen boundary instead of pretending external Rust modules are
Elixir modules.
defrustimpl groups defrust declarations into an inherent or trait Rust
impl block. The first argument of each method remains valid Elixir and must
be typed as R.ref(Target.t()) or R.mut_ref(Target.t()); RustQ renders it
as &self or &mut self respectively.
defrustmacro defines a small macro_rules! item from a Rusty-Elixir body.
Its arguments are Rust macro fragments (:expr by default, with :ty
supported for type arguments) while the body still uses ordinary Rusty-Elixir
forms such as calls, decode_as!/2, and inference-backed propagation.
Prefer @spec plus defrust for user-facing Rusty Elixir. Generated or
external Rust paths should normally be expressed as ordinary remote types such
as GeneratedOpts.OvalOpts.t(R.lifetime(:a)); use RustQ.Type markers such
as R.ref/1, R.nif_result/1, R.unit/0, R.slice/1, and R.lifetime/1
only where Elixir typespecs need Rust-specific precision.
RustQ.Meta.AST.functions/1 and function!/2 are the public structural
bridge for generators that consume compiled defrust functions; they are not
the normal function-authoring surface.
Preferred Rusty-Elixir body forms are ordinary Elixir where possible:
- final
:okunderNifResult<()>returnsOk(()) name = expressionlowers to Rustlet name = expression- method calls, field access, aliases, and Elixir tuples lower to their Rust equivalents
- plural alias calls such as
Atoms.fill()lower to snake-case Rust module calls such asatoms::fill() - a RustQ module named through
aliasis imported: its functions, methods, and types are known, andRuntime.decode(bytes)calls its Rustdecode. A module shares Rust it emits as it is fromtemplates/beside it, astemplates/runtime.rsforruntime.ex, or names it withprovides: - ordinary Elixir macros are expanded before lowering, so reusable body
fragments can use
defmacro,quote, andunquote - fallible calls in argument, return, case-scrutinee,
some(...),decode_as!, and many local-binding positions can infer Rust?from type metadata unwrap!(expression)is the explicit spelling for Rustexpression?; prefer inference when callable metadata is availableref(expression)/mut_ref(expression)spell explicit Rust borrows; many ordinary calls infer borrows from expected argument types- Closure arguments support ordinary tuple patterns and wildcards. Known
callable parameter types are available while lowering the closure body.
AST generators can additionally use
{pattern, type}closure arguments for explicit Rust annotations, without introducing new Elixir syntax. move(fn ... end)explicitly moves a closure's captures into the Rust closure. Clone shared values explicitly before capture when needed; RustQ does not insert clones or choose ownership policy. Ordinaryfnkeeps Rust's default capture behavior.deref(expression)spells Rust dereference and can propagate fallible reference access such asargs.first().ok_or(badarg())- Option branching should use Elixir
case, for examplecase maybe do {:some, value} -> ...; :none -> ... end; do not introduce Rust-shapedif_letsyntax at the authoring layer
Escape hatches such as raw_expr! remain low-level last resorts, not the
normal way to reference project-owned Rust modules or types.
Summary
Functions
Imports the defrust family of macros and collects the module's Rust definitions, which
are lowered when the module compiles. opts are validated by RustQ.Meta.Options.
Declares a public NIF entrypoint generated from a valid Elixir-shaped body.
Groups Rusty-Elixir methods into an inherent or trait Rust impl block.
Declares a private generated Rust helper from a valid Elixir-shaped body.
Functions
Imports the defrust family of macros and collects the module's Rust definitions, which
are lowered when the module compiles. opts are validated by RustQ.Meta.Options.
Declares a public NIF entrypoint generated from a valid Elixir-shaped body.
Groups Rusty-Elixir methods into an inherent or trait Rust impl block.
The first argument of every nested defrust declaration is the receiver. Its
spec must use R.ref(...) for &self or R.mut_ref(...) for &mut self.
defrustimpl Counter, vis: :crate do
@spec increment(R.mut_ref(R.path(:Counter)), R.i64()) :: R.i64()
defrust increment(self, amount), do: self.value + amount
end
defrustimpl Display, for: Counter do
@spec fmt(R.ref(R.path(:Counter)), R.path(:Formatter)) :: R.path(:FmtResult)
defrust fmt(self, formatter), do: formatter.write_str(self.label.as_str())
endSupported options are :for, :vis, :attrs, and :lifetimes.
Declares a private generated Rust helper from a valid Elixir-shaped body.