Skip to main content

native/rustq_nif/src/generated_ast.rs

// This file is generated by RustQ. Do not edit by hand.

use rustler::{Atom, Env, NifResult, Term};

use syn::{
    Arm, Expr, Field, FnArg, Item, ItemConst, ItemEnum, ItemFn, ItemImpl, ItemMod, ItemStatic,
    ItemStruct, ItemType, ItemUse, Pat, Path, Stmt, Type, Variant,
};

pub(crate) mod atoms {
    rustler::atoms! {
        ok, error
    }
}

pub(crate) mod ast_modules {
    pub(crate) const USE: &str = "Elixir.RustQ.Rust.AST.Use";
    pub(crate) const MODULE: &str = "Elixir.RustQ.Rust.AST.Module";
    pub(crate) const CONST: &str = "Elixir.RustQ.Rust.AST.Const";
    pub(crate) const STATIC: &str = "Elixir.RustQ.Rust.AST.Static";
    pub(crate) const TYPE_ALIAS: &str = "Elixir.RustQ.Rust.AST.TypeAlias";
    pub(crate) const MACRO_ITEM: &str = "Elixir.RustQ.Rust.AST.MacroItem";
    pub(crate) const MACRO_ITEM_CALL: &str = "Elixir.RustQ.Rust.AST.MacroItemCall";
    pub(crate) const IMPL: &str = "Elixir.RustQ.Rust.AST.Impl";
    pub(crate) const FUNCTION: &str = "Elixir.RustQ.Rust.AST.Function";
    pub(crate) const STRUCT: &str = "Elixir.RustQ.Rust.AST.Struct";
    pub(crate) const ENUM: &str = "Elixir.RustQ.Rust.AST.Enum";
    pub(crate) const TYPE_PATH: &str = "Elixir.RustQ.Rust.AST.TypePath";
    pub(crate) const TYPE_REF: &str = "Elixir.RustQ.Rust.AST.TypeRef";
    pub(crate) const TYPE_OPTION: &str = "Elixir.RustQ.Rust.AST.TypeOption";
    pub(crate) const TYPE_RESULT: &str = "Elixir.RustQ.Rust.AST.TypeResult";
    pub(crate) const TYPE_NIF_RESULT: &str = "Elixir.RustQ.Rust.AST.TypeNifResult";
    pub(crate) const TYPE_VEC: &str = "Elixir.RustQ.Rust.AST.TypeVec";
    pub(crate) const TYPE_SLICE: &str = "Elixir.RustQ.Rust.AST.TypeSlice";
    pub(crate) const TYPE_ARRAY: &str = "Elixir.RustQ.Rust.AST.TypeArray";
    pub(crate) const TYPE_RAW: &str = "Elixir.RustQ.Rust.AST.TypeRaw";
    pub(crate) const TYPE_UNIT: &str = "Elixir.RustQ.Rust.AST.TypeUnit";
    pub(crate) const LET: &str = "Elixir.RustQ.Rust.AST.Let";
    pub(crate) const LET_ELSE: &str = "Elixir.RustQ.Rust.AST.LetElse";
    pub(crate) const ASSIGN: &str = "Elixir.RustQ.Rust.AST.Assign";
    pub(crate) const EXPR_STMT: &str = "Elixir.RustQ.Rust.AST.ExprStmt";
    pub(crate) const RETURN: &str = "Elixir.RustQ.Rust.AST.Return";
    pub(crate) const EARLY_RETURN: &str = "Elixir.RustQ.Rust.AST.EarlyReturn";
    pub(crate) const IF_LET: &str = "Elixir.RustQ.Rust.AST.IfLet";
    pub(crate) const FOR: &str = "Elixir.RustQ.Rust.AST.For";
    pub(crate) const LOOP: &str = "Elixir.RustQ.Rust.AST.Loop";
    pub(crate) const BREAK: &str = "Elixir.RustQ.Rust.AST.Break";
    pub(crate) const CONTINUE: &str = "Elixir.RustQ.Rust.AST.Continue";
    pub(crate) const VAR: &str = "Elixir.RustQ.Rust.AST.Var";
    pub(crate) const PATH: &str = "Elixir.RustQ.Rust.AST.Path";
    pub(crate) const FIELD: &str = "Elixir.RustQ.Rust.AST.Field";
    pub(crate) const INDEX: &str = "Elixir.RustQ.Rust.AST.Index";
    pub(crate) const RANGE: &str = "Elixir.RustQ.Rust.AST.Range";
    pub(crate) const CAST: &str = "Elixir.RustQ.Rust.AST.Cast";
    pub(crate) const UNARY_OP: &str = "Elixir.RustQ.Rust.AST.UnaryOp";
    pub(crate) const PATH_CALL: &str = "Elixir.RustQ.Rust.AST.PathCall";
    pub(crate) const METHOD_CALL: &str = "Elixir.RustQ.Rust.AST.MethodCall";
    pub(crate) const STRUCT_LITERAL: &str = "Elixir.RustQ.Rust.AST.StructLiteral";
    pub(crate) const LOCAL_CALL: &str = "Elixir.RustQ.Rust.AST.LocalCall";
    pub(crate) const REF: &str = "Elixir.RustQ.Rust.AST.Ref";
    pub(crate) const TRY: &str = "Elixir.RustQ.Rust.AST.Try";
    pub(crate) const TUPLE: &str = "Elixir.RustQ.Rust.AST.Tuple";
    pub(crate) const VEC_LITERAL: &str = "Elixir.RustQ.Rust.AST.VecLiteral";
    pub(crate) const ARRAY_LITERAL: &str = "Elixir.RustQ.Rust.AST.ArrayLiteral";
    pub(crate) const CLOSURE: &str = "Elixir.RustQ.Rust.AST.Closure";
    pub(crate) const LITERAL: &str = "Elixir.RustQ.Rust.AST.Literal";
    pub(crate) const BYTE_STRING: &str = "Elixir.RustQ.Rust.AST.ByteString";
    pub(crate) const ESCAPE_EXPR: &str = "Elixir.RustQ.Rust.AST.EscapeExpr";
    pub(crate) const TOKEN_MACRO: &str = "Elixir.RustQ.Rust.AST.TokenMacro";
    pub(crate) const MACRO_CALL: &str = "Elixir.RustQ.Rust.AST.MacroCall";
    pub(crate) const ATOM_VALUE: &str = "Elixir.RustQ.Rust.AST.AtomValue";
    pub(crate) const NONE: &str = "Elixir.RustQ.Rust.AST.None";
    pub(crate) const SOME: &str = "Elixir.RustQ.Rust.AST.Some";
    pub(crate) const OK: &str = "Elixir.RustQ.Rust.AST.Ok";
    pub(crate) const ERR: &str = "Elixir.RustQ.Rust.AST.Err";
    pub(crate) const NIF_RAISE_ATOM: &str = "Elixir.RustQ.Rust.AST.NifRaiseAtom";
    pub(crate) const BLOCK_EXPR: &str = "Elixir.RustQ.Rust.AST.BlockExpr";
    pub(crate) const MATCH: &str = "Elixir.RustQ.Rust.AST.Match";
    pub(crate) const IF: &str = "Elixir.RustQ.Rust.AST.If";
    pub(crate) const BINARY_OP: &str = "Elixir.RustQ.Rust.AST.BinaryOp";
    pub(crate) const PAT_VAR: &str = "Elixir.RustQ.Rust.AST.PatVar";
    pub(crate) const PAT_WILDCARD: &str = "Elixir.RustQ.Rust.AST.PatWildcard";
    pub(crate) const PAT_PATH: &str = "Elixir.RustQ.Rust.AST.PatPath";
    pub(crate) const PAT_LITERAL: &str = "Elixir.RustQ.Rust.AST.PatLiteral";
    pub(crate) const PAT_NONE: &str = "Elixir.RustQ.Rust.AST.PatNone";
    pub(crate) const PAT_SOME: &str = "Elixir.RustQ.Rust.AST.PatSome";
    pub(crate) const PAT_ATOM_GUARD: &str = "Elixir.RustQ.Rust.AST.PatAtomGuard";
    pub(crate) const PAT_TUPLE: &str = "Elixir.RustQ.Rust.AST.PatTuple";
    pub(crate) const PAT_OK: &str = "Elixir.RustQ.Rust.AST.PatOk";
    pub(crate) const PAT_ERR: &str = "Elixir.RustQ.Rust.AST.PatErr";
    pub(crate) const PAT_PATH_TUPLE: &str = "Elixir.RustQ.Rust.AST.PatPathTuple";
    pub(crate) const PAT_STRUCT: &str = "Elixir.RustQ.Rust.AST.PatStruct";
}

pub(crate) fn atom(env: Env, name: &str) -> NifResult<Atom> {
    Atom::from_str(env, name)
}

pub(crate) fn required_field<'a>(term: Term<'a>, key: &str) -> NifResult<Term<'a>> {
    term.map_get(atom(term.get_env(), key)?)
}

pub(crate) fn optional_map_get<'a>(term: Term<'a>, key: &str) -> NifResult<Option<Term<'a>>> {
    match term.map_get(atom(term.get_env(), key)?) {
        Ok(value) => Ok(Some(value)),
        Err(_reason) => Ok(None),
    }
}

pub(crate) fn atom_key<'a>(term: Term<'a>, key: &str) -> NifResult<String> {
    let value = term.map_get(atom(term.get_env(), key)?)?;
    value.atom_to_string()
}

pub(crate) fn optional_atom_key<'a>(term: Term<'a>, key: &str) -> NifResult<Option<String>> {
    let value = term.map_get(atom(term.get_env(), key)?)?;
    if is_nil(value)? {
        Ok(None)
    } else {
        Ok(Some(value.atom_to_string()?))
    }
}

pub(crate) fn is_nil<'a>(term: Term<'a>) -> NifResult<bool> {
    Ok(term.is_atom() && term.atom_to_string()? == "nil")
}

pub(crate) fn struct_name<'a>(term: Term<'a>) -> NifResult<String> {
    let value = term.map_get(atom(term.get_env(), "__struct__")?)?;
    value.atom_to_string()
}

pub(crate) fn expect_struct<'a>(term: Term<'a>, expected: &str) -> NifResult<()> {
    if struct_name(term)? == expected {
        Ok(())
    } else {
        Err(rustler::Error::BadArg)
    }
}

pub(crate) fn required_expr<'a>(term: Term<'a>, key: &str) -> NifResult<Expr> {
    super::decode_expr(required_field(term, key)?)
}

pub(crate) fn required_expr_list<'a>(term: Term<'a>, key: &str) -> NifResult<Vec<Expr>> {
    super::decode_expr_list(required_field(term, key)?)
}

pub(crate) fn required_type<'a>(term: Term<'a>, key: &str) -> NifResult<Type> {
    super::decode_type(required_field(term, key)?)
}

pub(crate) fn required_path<'a>(term: Term<'a>, key: &str) -> NifResult<Path> {
    super::parse_ast_path(required_field(term, key)?)
}

pub(crate) fn required_string_list<'a>(term: Term<'a>, key: &str) -> NifResult<Vec<String>> {
    super::decode_string_list(required_field(term, key)?)
}

pub(crate) fn required_type_list<'a>(term: Term<'a>, key: &str) -> NifResult<Vec<Type>> {
    super::decode_type_list(required_field(term, key)?)
}

pub(crate) fn required_pat<'a>(term: Term<'a>, key: &str) -> NifResult<Pat> {
    super::decode_pat(required_field(term, key)?)
}

pub(crate) fn required_pat_list<'a>(term: Term<'a>, key: &str) -> NifResult<Vec<Pat>> {
    super::decode_pat_list(required_field(term, key)?)
}

pub(crate) fn required_arm_list<'a>(term: Term<'a>, key: &str) -> NifResult<Vec<Arm>> {
    super::decode_arm_list(required_field(term, key)?)
}

pub(crate) fn required_stmt_list<'a>(term: Term<'a>, key: &str) -> NifResult<Vec<Stmt>> {
    super::decode_stmt_list(required_field(term, key)?)
}

pub(crate) fn required_item_list<'a>(term: Term<'a>, key: &str) -> NifResult<Vec<Item>> {
    super::decode_item_list(required_field(term, key)?)
}

pub(crate) fn required_function_arg_list<'a>(term: Term<'a>, key: &str) -> NifResult<Vec<FnArg>> {
    super::decode_function_arg_list(required_field(term, key)?)
}

pub(crate) fn required_struct_field_list<'a>(term: Term<'a>, key: &str) -> NifResult<Vec<Field>> {
    super::decode_struct_field_list(required_field(term, key)?)
}

pub(crate) fn required_enum_variant_list<'a>(term: Term<'a>, key: &str) -> NifResult<Vec<Variant>> {
    super::decode_enum_variant_list(required_field(term, key)?)
}

pub(crate) fn decode_ast_item(term: Term) -> NifResult<Item> {
    match struct_name(term)?.as_str() {
        ast_modules::USE => Ok(Item::Use(decode_ast_use(term)?)),
        ast_modules::MODULE => Ok(Item::Mod(decode_ast_module(term)?)),
        ast_modules::CONST => Ok(Item::Const(decode_ast_const(term)?)),
        ast_modules::STATIC => Ok(Item::Static(decode_ast_static(term)?)),
        ast_modules::TYPE_ALIAS => Ok(Item::Type(decode_ast_type_alias(term)?)),
        ast_modules::MACRO_ITEM => decode_ast_macro_item(term),
        ast_modules::MACRO_ITEM_CALL => decode_ast_macro_item_call(term),
        ast_modules::IMPL => Ok(Item::Impl(decode_ast_impl(term)?)),
        ast_modules::FUNCTION => Ok(Item::Fn(decode_ast_function(term)?)),
        ast_modules::STRUCT => Ok(Item::Struct(decode_ast_struct(term)?)),
        ast_modules::ENUM => Ok(Item::Enum(decode_ast_enum(term)?)),
        _ => Err(rustler::Error::BadArg),
    }
}

pub(crate) fn decode_ast_type(term: Term) -> NifResult<Type> {
    match struct_name(term)?.as_str() {
        ast_modules::TYPE_PATH => decode_type_path(term),
        ast_modules::TYPE_REF => decode_type_ref(term),
        ast_modules::TYPE_OPTION => decode_type_option(term),
        ast_modules::TYPE_RESULT => decode_type_result(term),
        ast_modules::TYPE_NIF_RESULT => decode_type_nif_result(term),
        ast_modules::TYPE_VEC => decode_type_vec(term),
        ast_modules::TYPE_SLICE => decode_type_slice(term),
        ast_modules::TYPE_ARRAY => decode_type_array(term),
        ast_modules::TYPE_RAW => decode_type_raw(term),
        ast_modules::TYPE_UNIT => decode_type_unit(term),
        _ => Err(rustler::Error::BadArg),
    }
}

pub(crate) fn decode_ast_pat(term: Term) -> NifResult<Pat> {
    match struct_name(term)?.as_str() {
        ast_modules::PAT_VAR => decode_pat_var(term),
        ast_modules::PAT_WILDCARD => decode_pat_wildcard(term),
        ast_modules::PAT_PATH => decode_pat_path(term),
        ast_modules::PAT_LITERAL => decode_pat_literal(term),
        ast_modules::PAT_NONE => decode_pat_none(term),
        ast_modules::PAT_SOME => decode_pat_some(term),
        ast_modules::PAT_ATOM_GUARD => super::decode_pat_atom_guard(term),
        ast_modules::PAT_TUPLE => decode_pat_tuple(term),
        ast_modules::PAT_OK => decode_pat_ok(term),
        ast_modules::PAT_ERR => decode_pat_err(term),
        ast_modules::PAT_PATH_TUPLE => decode_pat_path_tuple(term),
        ast_modules::PAT_STRUCT => decode_pat_struct(term),
        _ => Err(rustler::Error::BadArg),
    }
}

pub(crate) fn decode_ast_stmt(term: Term) -> NifResult<Stmt> {
    match struct_name(term)?.as_str() {
        ast_modules::LET => decode_stmt_let(term),
        ast_modules::LET_ELSE => decode_stmt_let_else(term),
        ast_modules::ASSIGN => decode_stmt_assign(term),
        ast_modules::EXPR_STMT => decode_stmt_expr_stmt(term),
        ast_modules::RETURN => decode_stmt_return(term),
        ast_modules::EARLY_RETURN => decode_stmt_early_return(term),
        ast_modules::IF_LET => decode_stmt_if_let(term),
        ast_modules::FOR => decode_stmt_for(term),
        ast_modules::LOOP => decode_stmt_loop(term),
        ast_modules::BREAK => decode_stmt_break(term),
        ast_modules::CONTINUE => decode_stmt_continue(term),
        _ => Err(rustler::Error::BadArg),
    }
}

pub(crate) fn decode_ast_expr(term: Term) -> NifResult<Expr> {
    match struct_name(term)?.as_str() {
        ast_modules::VAR => decode_expr_var(term),
        ast_modules::PATH => decode_expr_path(term),
        ast_modules::FIELD => decode_expr_field(term),
        ast_modules::INDEX => decode_expr_index(term),
        ast_modules::RANGE => decode_expr_range(term),
        ast_modules::CAST => decode_expr_cast(term),
        ast_modules::UNARY_OP => decode_expr_unary_op(term),
        ast_modules::PATH_CALL => decode_expr_path_call(term),
        ast_modules::METHOD_CALL => decode_expr_method_call(term),
        ast_modules::STRUCT_LITERAL => decode_expr_struct_literal(term),
        ast_modules::LOCAL_CALL => decode_expr_local_call(term),
        ast_modules::REF => decode_expr_ref(term),
        ast_modules::TRY => decode_expr_try(term),
        ast_modules::TUPLE => decode_expr_tuple(term),
        ast_modules::VEC_LITERAL => decode_expr_vec_literal(term),
        ast_modules::ARRAY_LITERAL => decode_expr_array_literal(term),
        ast_modules::CLOSURE => decode_expr_closure(term),
        ast_modules::LITERAL => decode_expr_literal(term),
        ast_modules::BYTE_STRING => decode_expr_byte_string(term),
        ast_modules::ESCAPE_EXPR => decode_expr_escape_expr(term),
        ast_modules::TOKEN_MACRO => decode_expr_token_macro(term),
        ast_modules::MACRO_CALL => decode_expr_macro_call(term),
        ast_modules::ATOM_VALUE => decode_expr_atom_value(term),
        ast_modules::NONE => decode_expr_none(term),
        ast_modules::SOME => decode_expr_some(term),
        ast_modules::OK => decode_expr_ok(term),
        ast_modules::ERR => decode_expr_err(term),
        ast_modules::NIF_RAISE_ATOM => decode_expr_nif_raise_atom(term),
        ast_modules::BLOCK_EXPR => decode_expr_block_expr(term),
        ast_modules::MATCH => decode_expr_match(term),
        ast_modules::IF => decode_expr_if(term),
        ast_modules::BINARY_OP => decode_expr_binary_op(term),
        _ => Err(rustler::Error::BadArg),
    }
}

pub(crate) fn decode_ast_use<'a>(term: Term<'a>) -> NifResult<ItemUse> {
    expect_struct(term, "Elixir.RustQ.Rust.AST.Use")?;
    let parts = required_field(term, "parts")?;
    if is_nil(parts)? {
        let group = required_field(term, "group")?;
        if is_nil(group)? {
            let tree = super::string_field(term, "tree")?;
            super::parse_item_use(tree)
        } else {
            super::parse_item_use_group_term(group)
        }
    } else {
        let parts = super::decode_string_list(parts)?;
        super::parse_item_use_path(parts)
    }
}

pub(crate) fn decode_ast_module<'a>(term: Term<'a>) -> NifResult<ItemMod> {
    expect_struct(term, "Elixir.RustQ.Rust.AST.Module")?;
    let name = super::format_ident_value(atom_key(term, "name")?);
    let vis = super::decode_vis(required_field(term, "vis")?)?;
    let items = required_item_list(term, "items")?;
    super::parse_item_module(name, vis, items)
}

pub(crate) fn decode_ast_impl<'a>(term: Term<'a>) -> NifResult<ItemImpl> {
    expect_struct(term, "Elixir.RustQ.Rust.AST.Impl")?;
    let target = required_type(term, "target")?;
    let trait_path = super::decode_optional_type_field(term, "trait")?;
    let impl_items = required_item_list(term, "items")?;
    let attrs = super::decode_attribute_list(required_field(term, "attrs")?)?;
    let lifetimes = decode_lifetime_list(required_field(term, "lifetimes")?)?;
    super::parse_item_impl(target, trait_path, impl_items, attrs, lifetimes)
}

pub(crate) fn decode_ast_const<'a>(term: Term<'a>) -> NifResult<ItemConst> {
    expect_struct(term, "Elixir.RustQ.Rust.AST.Const")?;
    let name = super::format_ident_value(atom_key(term, "name")?);
    let ty = required_type(term, "type")?;
    let expr = required_expr(term, "expr")?;
    let vis = super::decode_vis(required_field(term, "vis")?)?;
    super::parse_item_const(name, ty, expr, vis)
}

pub(crate) fn decode_ast_type_alias<'a>(term: Term<'a>) -> NifResult<ItemType> {
    expect_struct(term, "Elixir.RustQ.Rust.AST.TypeAlias")?;
    let name = super::format_ident_value(atom_key(term, "name")?);
    let ty = required_type(term, "type")?;
    let vis = super::decode_vis(required_field(term, "vis")?)?;
    super::parse_item_type(name, ty, vis)
}

pub(crate) fn decode_ast_static<'a>(term: Term<'a>) -> NifResult<ItemStatic> {
    expect_struct(term, "Elixir.RustQ.Rust.AST.Static")?;
    let name = super::format_ident_value(atom_key(term, "name")?);
    let ty = required_type(term, "type")?;
    let expr = required_expr(term, "expr")?;
    let mutable = required_field(term, "mutable")?.decode()?;
    let vis = super::decode_vis(required_field(term, "vis")?)?;
    super::parse_item_static(name, ty, expr, mutable, vis)
}

pub(crate) fn decode_ast_function<'a>(term: Term<'a>) -> NifResult<ItemFn> {
    expect_struct(term, "Elixir.RustQ.Rust.AST.Function")?;
    let name = super::format_ident_value(atom_key(term, "name")?);
    let vis = super::decode_vis(required_field(term, "vis")?)?;
    let args = required_function_arg_list(term, "args")?;
    let returns = required_type(term, "returns")?;
    let lifetime = optional_atom_key(term, "lifetime")?;
    let stmts = required_stmt_list(term, "body")?;
    let attrs = super::decode_attribute_list(required_field(term, "attrs")?)?;
    super::parse_item_function_args(name, vis, args, returns, lifetime, stmts, attrs)
}

pub(crate) fn decode_derive_path_list<'a>(term: Term<'a>) -> NifResult<Vec<Path>> {
    let terms = super::decode_derive_path_terms(term)?;
    terms
        .into_iter()
        .map(|derive_path| super::decode_path_value(derive_path))
        .collect()
}

pub(crate) fn decode_ast_struct<'a>(term: Term<'a>) -> NifResult<ItemStruct> {
    expect_struct(term, "Elixir.RustQ.Rust.AST.Struct")?;
    let name = super::format_ident_value(atom_key(term, "name")?);
    let vis = super::decode_vis(required_field(term, "vis")?)?;
    let derive = super::decode_derive(required_field(term, "derive")?)?;
    let lifetime = optional_atom_key(term, "lifetime")?;
    let fields = required_struct_field_list(term, "fields")?;
    let attrs = super::decode_attribute_list(required_field(term, "attrs")?)?;
    super::parse_item_struct(name, vis, derive, lifetime, fields, attrs)
}

pub(crate) fn decode_ast_macro_item<'a>(term: Term<'a>) -> NifResult<Item> {
    expect_struct(term, "Elixir.RustQ.Rust.AST.MacroItem")?;
    let source = super::string_field(term, "source")?;
    super::parse_macro_item(source)
}

pub(crate) fn decode_ast_macro_item_call<'a>(term: Term<'a>) -> NifResult<Item> {
    expect_struct(term, "Elixir.RustQ.Rust.AST.MacroItemCall")?;
    let path = required_path(term, "path")?;
    let args = super::decode_macro_item_arg_list(required_field(term, "args")?)?;
    super::parse_macro_item_call(path, args)
}

pub(crate) fn decode_ast_enum<'a>(term: Term<'a>) -> NifResult<ItemEnum> {
    expect_struct(term, "Elixir.RustQ.Rust.AST.Enum")?;
    let name = super::format_ident_value(atom_key(term, "name")?);
    let vis = super::decode_vis(required_field(term, "vis")?)?;
    let derive = super::decode_derive(required_field(term, "derive")?)?;
    let variants = required_enum_variant_list(term, "variants")?;
    let attrs = super::decode_attribute_list(required_field(term, "attrs")?)?;
    super::parse_item_enum(name, vis, derive, variants, attrs)
}

pub(crate) fn decode_function_arg<'a>(term: Term<'a>) -> NifResult<FnArg> {
    expect_struct(term, "Elixir.RustQ.Rust.AST.FunctionArg")?;
    let receiver = required_field(term, "receiver")?.decode::<bool>()?;
    let mutable = required_field(term, "mutable")?.decode::<bool>()?;
    if receiver {
        super::parse_function_receiver(mutable)
    } else {
        let name = super::format_ident_value(atom_key(term, "name")?);
        let ty = required_type(term, "type")?;
        super::parse_function_arg(name, ty)
    }
}

pub(crate) fn decode_struct_field<'a>(term: Term<'a>) -> NifResult<Field> {
    expect_struct(term, "Elixir.RustQ.Rust.AST.StructField")?;
    let name = super::format_ident_value(atom_key(term, "name")?);
    let ty = required_type(term, "type")?;
    let vis = super::decode_vis(required_field(term, "vis")?)?;
    super::parse_struct_field(name, ty, vis)
}

pub(crate) fn decode_enum_variant<'a>(term: Term<'a>) -> NifResult<Variant> {
    expect_struct(term, "Elixir.RustQ.Rust.AST.EnumVariant")?;
    let name = super::format_ident_value(atom_key(term, "name")?);
    let tuple = required_type_list(term, "tuple")?;
    super::parse_enum_variant(name, tuple)
}

pub(crate) fn path_parts<'a>(term: Term<'a>) -> NifResult<String> {
    let parts = super::decode_string_list(term)?;
    Ok(parts.join("::"))
}

pub(crate) fn decode_lifetime_list<'a>(term: Term<'a>) -> NifResult<Vec<String>> {
    super::decode_string_list(term)
}

pub(crate) fn decode_type_path<'a>(term: Term<'a>) -> NifResult<Type> {
    let parts = required_string_list(term, "parts")?;
    let lifetimes = decode_lifetime_list(required_field(term, "lifetimes")?)?;
    let generics = required_type_list(term, "generics")?;
    super::parse_type_path_with_generics(parts, lifetimes, generics)
}

pub(crate) fn decode_type_unit<'a>(term: Term<'a>) -> NifResult<Type> {
    super::parse_type_unit(term)
}

pub(crate) fn decode_type_raw<'a>(term: Term<'a>) -> NifResult<Type> {
    let source = required_field(term, "source")?.decode()?;
    super::parse_type_raw(source)
}

pub(crate) fn decode_type_ref<'a>(term: Term<'a>) -> NifResult<Type> {
    let inner = required_type(term, "inner")?;
    let mutable = required_field(term, "mutable")?.decode()?;
    let lifetime = optional_atom_key(term, "lifetime")?;
    super::parse_type_ref(inner, mutable, lifetime)
}

pub(crate) fn decode_type_option<'a>(term: Term<'a>) -> NifResult<Type> {
    let inner = required_type(term, "inner")?;
    super::parse_type_generic("Option", vec![inner])
}

pub(crate) fn decode_type_result<'a>(term: Term<'a>) -> NifResult<Type> {
    let ok = required_type(term, "ok")?;
    let error = required_type(term, "error")?;
    super::parse_type_generic("Result", vec![ok, error])
}

pub(crate) fn decode_type_nif_result<'a>(term: Term<'a>) -> NifResult<Type> {
    let inner = required_type(term, "inner")?;
    super::parse_type_generic("NifResult", vec![inner])
}

pub(crate) fn decode_type_vec<'a>(term: Term<'a>) -> NifResult<Type> {
    let inner = required_type(term, "inner")?;
    super::parse_type_generic("Vec", vec![inner])
}

pub(crate) fn decode_type_slice<'a>(term: Term<'a>) -> NifResult<Type> {
    let inner = required_type(term, "inner")?;
    super::parse_type_slice(inner)
}

pub(crate) fn decode_type_array<'a>(term: Term<'a>) -> NifResult<Type> {
    let inner = required_type(term, "inner")?;
    let size = required_field(term, "size")?;
    super::parse_type_array(inner, size)
}

pub(crate) fn decode_pat_var<'a>(term: Term<'a>) -> NifResult<Pat> {
    let ident = super::format_ident_value(atom_key(term, "name")?);
    let mutable = required_field(term, "mutable")?.decode()?;
    super::parse_var_pat(ident, mutable)
}

pub(crate) fn decode_pat_wildcard<'a>(term: Term<'a>) -> NifResult<Pat> {
    super::parse_wildcard_pat(term)
}

pub(crate) fn decode_pat_none<'a>(term: Term<'a>) -> NifResult<Pat> {
    super::parse_none_pat(term)
}

pub(crate) fn decode_pat_path<'a>(term: Term<'a>) -> NifResult<Pat> {
    let path = required_path(term, "path")?;
    super::parse_path_pat(path)
}

pub(crate) fn decode_pat_literal<'a>(term: Term<'a>) -> NifResult<Pat> {
    super::decode_pat_literal_value(required_field(term, "value")?)
}

pub(crate) fn decode_pat_some<'a>(term: Term<'a>) -> NifResult<Pat> {
    let pat = required_pat(term, "pattern")?;
    super::parse_some_pat(pat)
}

pub(crate) fn decode_pat_ok<'a>(term: Term<'a>) -> NifResult<Pat> {
    let pat = required_pat(term, "pattern")?;
    super::parse_ok_pat(pat)
}

pub(crate) fn decode_pat_err<'a>(term: Term<'a>) -> NifResult<Pat> {
    let pat = required_pat(term, "pattern")?;
    super::parse_err_pat(pat)
}

pub(crate) fn decode_pat_tuple<'a>(term: Term<'a>) -> NifResult<Pat> {
    let patterns = required_pat_list(term, "patterns")?;
    super::parse_tuple_pat(patterns)
}

pub(crate) fn decode_pat_path_tuple<'a>(term: Term<'a>) -> NifResult<Pat> {
    let path = required_path(term, "path")?;
    let patterns = required_pat_list(term, "patterns")?;
    super::parse_path_tuple_pat(path, patterns)
}

pub(crate) fn decode_pat_struct<'a>(term: Term<'a>) -> NifResult<Pat> {
    let path = required_path(term, "path")?;
    let fields = super::decode_pat_struct_fields(required_field(term, "fields")?)?;
    super::parse_struct_pat(path, fields)
}

pub(crate) fn decode_stmt_assign<'a>(term: Term<'a>) -> NifResult<Stmt> {
    let target = required_expr(term, "target")?;
    let expr = required_expr(term, "expr")?;
    super::parse_assign_stmt(target, expr)
}

pub(crate) fn decode_stmt_expr_stmt<'a>(term: Term<'a>) -> NifResult<Stmt> {
    let expr = required_expr(term, "expr")?;
    super::parse_expr_stmt(expr)
}

pub(crate) fn decode_stmt_return<'a>(term: Term<'a>) -> NifResult<Stmt> {
    let expr = required_expr(term, "expr")?;
    Ok(Stmt::Expr(expr, None))
}

pub(crate) fn decode_stmt_early_return<'a>(term: Term<'a>) -> NifResult<Stmt> {
    let expr = required_expr(term, "expr")?;
    super::parse_return_stmt(expr)
}

pub(crate) fn decode_stmt_if_let<'a>(term: Term<'a>) -> NifResult<Stmt> {
    let pattern = required_pat(term, "pattern")?;
    let expr = required_expr(term, "expr")?;
    let then_block = super::decode_block(required_field(term, "then")?)?;
    let else_block = super::decode_optional_block_field(term, "else")?;
    super::parse_if_let_stmt(pattern, expr, then_block, else_block)
}

pub(crate) fn decode_stmt_for<'a>(term: Term<'a>) -> NifResult<Stmt> {
    let pattern = required_pat(term, "pattern")?;
    let expr = required_expr(term, "expr")?;
    let body = super::decode_block(required_field(term, "body")?)?;
    super::parse_for_stmt(pattern, expr, body)
}

pub(crate) fn decode_stmt_loop<'a>(term: Term<'a>) -> NifResult<Stmt> {
    let body = super::decode_block(required_field(term, "body")?)?;
    super::parse_loop_stmt(body)
}

pub(crate) fn decode_stmt_break<'a>(term: Term<'a>) -> NifResult<Stmt> {
    let expr = super::decode_optional_expr_field(term, "expr")?;
    super::parse_break_stmt(expr)
}

pub(crate) fn decode_stmt_continue<'a>(_term: Term<'a>) -> NifResult<Stmt> {
    super::parse_continue_stmt()
}

pub(crate) fn decode_stmt_let<'a>(term: Term<'a>) -> NifResult<Stmt> {
    let pattern = required_pat(term, "pattern")?;
    let mutable = required_field(term, "mutable")?.decode()?;
    let pat_tokens = super::decode_let_pattern(pattern, mutable)?;
    let expr = required_expr(term, "expr")?;
    let ty = super::decode_optional_type_field(term, "type")?;
    super::parse_let_stmt(pat_tokens, ty, expr)
}

pub(crate) fn decode_stmt_let_else<'a>(term: Term<'a>) -> NifResult<Stmt> {
    let pattern = required_pat(term, "pattern")?;
    let expr = required_expr(term, "expr")?;
    let else_block = super::decode_block(required_field(term, "else")?)?;
    super::parse_let_else_stmt(pattern, expr, else_block)
}

pub(crate) fn decode_arm<'a>(term: Term<'a>) -> NifResult<Arm> {
    expect_struct(term, "Elixir.RustQ.Rust.AST.Arm")?;
    let pat_term = required_field(term, "pattern")?;
    let guard = super::decode_optional_expr_field(term, "guard")?;
    let block = super::decode_block(required_field(term, "body")?)?;
    if struct_name(pat_term)? == "Elixir.RustQ.Rust.AST.PatAtomGuard" {
        super::decode_atom_guard_arm(pat_term, block)
    } else {
        let pat = super::decode_pat(pat_term)?;
        super::parse_guarded_block_arm(pat, guard, block)
    }
}

pub(crate) fn decode_expr_var<'a>(term: Term<'a>) -> NifResult<Expr> {
    let ident = super::format_ident_value(atom_key(term, "name")?);
    super::parse_ident_expr(ident)
}

pub(crate) fn decode_expr_path<'a>(term: Term<'a>) -> NifResult<Expr> {
    let path = super::parse_ast_path(term)?;
    super::parse_path_expr(path)
}

pub(crate) fn decode_expr_atom_value<'a>(term: Term<'a>) -> NifResult<Expr> {
    let name = super::format_ident_value(atom_key(term, "name")?);
    let module = super::decode_string_list(required_field(term, "module")?)?;
    super::parse_atom_value_expr(module, name)
}

pub(crate) fn decode_expr_field<'a>(term: Term<'a>) -> NifResult<Expr> {
    let receiver = required_expr(term, "receiver")?;
    let field = required_field(term, "field")?;
    super::parse_field_expr(receiver, field)
}

pub(crate) fn decode_expr_index<'a>(term: Term<'a>) -> NifResult<Expr> {
    let receiver = required_expr(term, "receiver")?;
    let index = required_expr(term, "index")?;
    super::parse_index_expr(receiver, index)
}

pub(crate) fn decode_expr_range<'a>(term: Term<'a>) -> NifResult<Expr> {
    let start = super::decode_optional_expr_field(term, "start")?;
    let stop = super::decode_optional_expr_field(term, "stop")?;
    super::parse_range_expr(start, stop)
}

pub(crate) fn decode_expr_cast<'a>(term: Term<'a>) -> NifResult<Expr> {
    let expr = required_expr(term, "expr")?;
    let ty = required_type(term, "type")?;
    super::parse_cast_expr(expr, ty)
}

pub(crate) fn decode_expr_unary_op<'a>(term: Term<'a>) -> NifResult<Expr> {
    let op = atom_key(term, "op")?;
    let expr = required_expr(term, "expr")?;
    match op.as_str() {
        "not" => super::parse_unary_expr(op, expr),
        "neg" => super::parse_unary_expr(op, expr),
        "deref" => super::parse_unary_expr(op, expr),
        _ => Err(rustler::Error::BadArg),
    }
}

pub(crate) fn decode_expr_path_call<'a>(term: Term<'a>) -> NifResult<Expr> {
    let path = required_path(term, "path")?;
    let args = required_expr_list(term, "args")?;
    let generics = required_type_list(term, "generics")?;
    super::parse_path_call_expr(path, args, generics)
}

pub(crate) fn decode_expr_method_call<'a>(term: Term<'a>) -> NifResult<Expr> {
    let receiver = required_expr(term, "receiver")?;
    let method = super::format_ident_value(atom_key(term, "method")?);
    let args = required_expr_list(term, "args")?;
    let generics = required_type_list(term, "generics")?;
    super::parse_method_call_expr(receiver, method, args, generics)
}

pub(crate) fn decode_expr_local_call<'a>(term: Term<'a>) -> NifResult<Expr> {
    let name = atom_key(term, "name")?;
    let args = required_expr_list(term, "args")?;
    super::parse_local_call(name, args)
}

pub(crate) fn decode_expr_ref<'a>(term: Term<'a>) -> NifResult<Expr> {
    let expr = required_expr(term, "expr")?;
    let mutable = required_field(term, "mutable")?.decode()?;
    super::parse_ref_expr(expr, mutable)
}

pub(crate) fn decode_expr_struct_literal<'a>(term: Term<'a>) -> NifResult<Expr> {
    let path = required_expr(term, "path")?;
    let fields = super::decode_struct_literal_fields(required_field(term, "fields")?)?;
    super::parse_struct_literal_expr(path, fields)
}

pub(crate) fn decode_expr_nif_raise_atom<'a>(term: Term<'a>) -> NifResult<Expr> {
    let name = atom_key(term, "name")?;
    super::parse_raise_atom_expr(name)
}

pub(crate) fn decode_expr_binary_op<'a>(term: Term<'a>) -> NifResult<Expr> {
    let left = required_expr(term, "left")?;
    let right = required_expr(term, "right")?;
    let op = atom_key(term, "op")?;
    super::parse_binary_expr(left, op, right)
}

pub(crate) fn decode_expr_block_expr<'a>(term: Term<'a>) -> NifResult<Expr> {
    let block = super::decode_block(required_field(term, "body")?)?;
    super::parse_block_expr(block)
}

pub(crate) fn decode_expr_match<'a>(term: Term<'a>) -> NifResult<Expr> {
    let expr = required_expr(term, "expr")?;
    let arms = required_arm_list(term, "arms")?;
    super::parse_match_expr(expr, arms)
}

pub(crate) fn decode_expr_if<'a>(term: Term<'a>) -> NifResult<Expr> {
    let condition = required_expr(term, "condition")?;
    let then_block = super::decode_block(required_field(term, "then")?)?;
    let else_block = super::decode_optional_block_field(term, "else")?;
    super::parse_if_expr(condition, then_block, else_block)
}

pub(crate) fn decode_expr_tuple<'a>(term: Term<'a>) -> NifResult<Expr> {
    let values = required_expr_list(term, "values")?;
    super::parse_tuple_expr(values)
}

pub(crate) fn decode_expr_vec_literal<'a>(term: Term<'a>) -> NifResult<Expr> {
    let values = required_expr_list(term, "values")?;
    super::parse_vec_expr(values)
}

pub(crate) fn decode_expr_array_literal<'a>(term: Term<'a>) -> NifResult<Expr> {
    let values = required_expr_list(term, "values")?;
    super::parse_array_expr(values)
}

pub(crate) fn decode_expr_closure<'a>(term: Term<'a>) -> NifResult<Expr> {
    let args = super::decode_ident_list(required_field(term, "args")?)?;
    let body = required_expr(term, "body")?;
    super::parse_closure_expr(args, body)
}

pub(crate) fn decode_expr_macro_call<'a>(term: Term<'a>) -> NifResult<Expr> {
    let path = required_path(term, "path")?;
    let args = required_expr_list(term, "args")?;
    super::parse_macro_call_expr(path, args)
}

pub(crate) fn decode_expr_byte_string<'a>(term: Term<'a>) -> NifResult<Expr> {
    let value = super::string_field(term, "value")?;
    super::parse_byte_string_expr(value)
}

pub(crate) fn decode_expr_escape_expr<'a>(term: Term<'a>) -> NifResult<Expr> {
    let source = super::string_field(term, "source")?;
    super::parse_expr(&source)
}

pub(crate) fn decode_expr_token_macro<'a>(term: Term<'a>) -> NifResult<Expr> {
    let path = super::path_parts(required_field(required_field(term, "path")?, "parts")?)?;
    let tokens = super::string_field(term, "tokens")?;
    super::parse_expr(format!("{}!({})", path, tokens))
}

pub(crate) fn decode_expr_ok<'a>(term: Term<'a>) -> NifResult<Expr> {
    let optional_expr = super::decode_optional_expr_field(term, "expr")?;
    super::parse_ok_expr(optional_expr)
}

pub(crate) fn decode_expr_none<'a>(term: Term<'a>) -> NifResult<Expr> {
    super::parse_none_expr(term)
}

pub(crate) fn decode_expr_literal<'a>(term: Term<'a>) -> NifResult<Expr> {
    super::decode_literal_expr(required_field(term, "value")?)
}

pub(crate) fn decode_expr_try<'a>(term: Term<'a>) -> NifResult<Expr> {
    let expr = required_expr(term, "expr")?;
    super::parse_try_expr(expr)
}

pub(crate) fn decode_expr_some<'a>(term: Term<'a>) -> NifResult<Expr> {
    let expr = required_expr(term, "expr")?;
    super::parse_some_expr(expr)
}

pub(crate) fn decode_expr_err<'a>(term: Term<'a>) -> NifResult<Expr> {
    let expr = required_expr(term, "expr")?;
    super::parse_err_expr(expr)
}