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() - 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 typesderef(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
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
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.