defmodule Mix.Tasks.Rustq.Templates.Check do
@moduledoc """
Verifies that RustQ template fixtures still compile against the generated Rust support code.
"""
use Mix.Task
alias RustQ.Rust.AST.Builder, as: A
@shortdoc "Checks RustQ's Rustler helper templates"
@fixture Path.join(["fixtures", "rustler_template_check"])
@impl Mix.Task
def run(_args) do
fixture = fixture_path()
manifest = Path.join(fixture, "Cargo.toml")
fixture
|> Path.join("src/generated.rs")
|> File.write!(generated_source())
cargo(["fmt", "--manifest-path", manifest, "--", "--check"])
cargo(["check", "--manifest-path", manifest])
cargo([
"clippy",
"--manifest-path",
manifest,
"--",
"-D",
"warnings"
])
end
defp generated_source do
RustQ.render!("__rq_items!();", "generated.rs",
preamble:
"// This file is generated by mix rustq.templates.check. Do not edit by hand.\n\n",
splice: [items: generated_items()]
)
end
defp generated_items do
List.flatten([
RustQ.Rustler.resource(:Document, fields: [nodes: {:vec, :Node}]),
RustQ.Rustler.resource_type(:Document),
RustQ.Rustler.resource_decoder(:Document),
RustQ.Rustler.term_helpers(type_key: "atoms::r#type()"),
RustQ.Rustler.atom_decoder(:decode_node_kind,
returns: :NodeKind,
cases: [text: "NodeKind::Text", space: "NodeKind::Space"]
),
RustQ.Rustler.atom_dispatch(:dispatch_node,
args: [kind: :Atom],
on: "kind",
cases: [text: "decode_text()", space: "decode_space()"]
),
RustQ.Rustler.opts_helpers(),
RustQ.Rustler.term_decoder(:ProgramInput,
fields: [body: [type: {:vec, "Term<'a>"}, key: "atoms::body()", required: true]]
),
RustQ.Rustler.term_decoder(:IfStatementInput,
fields: [
test: [type: "Term<'a>", key: "atoms::test()", required: true],
consequent: [type: "Term<'a>", key: "atoms::consequent()", required: true],
alternate: [type: {:option, "Term<'a>"}, key: "atoms::alternate()"]
]
),
RustQ.Rustler.nif_struct(:ExText, "Folio.Content.Text",
attrs: ["allow(dead_code)"],
fields: [text: :String, size: {:option, :String}]
),
RustQ.Rustler.nif_struct(:ExSpace, "Folio.Content.Space",
attrs: ["allow(dead_code)"],
fields: []
),
RustQ.Rustler.tagged_enum(:ExContent,
attrs: [A.allow_attr(:dead_code)],
tag: A.call(:atom_struct),
variants: [
Text: [type: :ExText, module: "Elixir.Folio.Content.Text"],
Space: [type: :ExSpace, module: "Elixir.Folio.Content.Space"]
]
),
RustQ.Rustler.cached_atoms([:ok, {:node_changes, "nodeChanges"}]),
RustQ.Rustler.term_builders(),
RustQ.Rustler.nif_term_builders()
])
end
defp fixture_path do
:rustq
|> :code.priv_dir()
|> List.to_string()
|> Path.join(@fixture)
end
defp cargo(args) do
{_, status} = System.cmd("cargo", args, into: IO.stream(), stderr_to_stdout: true)
if status != 0 do
Mix.raise("cargo #{Enum.join(args, " ")} failed")
end
end
end