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