async-codegen 0.12.1

Minimalist async-IO code generation framework.
Documentation
/*
 * Copyright © 2025 Anand Beh
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
use crate::common::{CombinedSeq, NoOp, NoOpSeq, SingularSeq, Str, StrArrSeq};
use crate::context::{EmptyContext, SingularContext};
use crate::rust::{
    AnonTuple, ArrayFromElements, ArrayInit, AssociatedItem, BoundedTypeVar, CanHaveAttributes,
    Cfg, Dereference, Edition, FunctionBodyDeclare, FunctionDef, FunctionParam, MemberAccess,
    ModPub, ModUnsafe, ModUnsafeExtern, MustUse, NamedTuple, NoMangle, Parameterized, RefOf,
    Target, TraitImpl, Turbofish, TypeAsTrait, UseType,
};
use crate::util::InMemoryOutput;

#[test]
fn edition_order() {
    assert!(Edition::Rust2018 < Edition::Rust2021);
    assert!(Edition::Rust2018 < Edition::Rust2024);
}

#[test]
fn use_type() {
    let string =
        InMemoryOutput::print_output(EmptyContext, &UseType(Str("crate::common::NoOpSeq")));
    assert_eq!("use crate::common::NoOpSeq;\n", string)
}

#[test]
fn type_as_trait_associated_item() {
    let string = InMemoryOutput::print_output(
        EmptyContext,
        &AssociatedItem(TypeAsTrait(Str("E"), Str("MyTrait")), Str("AssocItem")),
    );
    assert_eq!("<E as MyTrait>::AssocItem", string);
}

#[test]
fn conditional_function_on_wasm() {
    let string = InMemoryOutput::print_output(
        EmptyContext,
        &FunctionDef {
            mods: CombinedSeq(SingularSeq(ModPub), SingularSeq(ModUnsafeExtern(Str("C")))),
            name: Str("incoming"),
            args: SingularSeq(FunctionParam(Str("data"), Str("u16"))),
            return_type: Str("()"),
            where_conds: NoOpSeq,
            body: FunctionBodyDeclare,
        }
        .with_attributes(SingularSeq(Cfg(Target::Family(Str("wasm"))))),
    );
    assert_eq!(
        "#[cfg(target_family = \"wasm\")]\npub unsafe extern \"C\" fn incoming(data: u16) -> ();\n\n",
        string
    );
}

#[test]
fn function_with_attributes_on_params() {
    let string =
        InMemoryOutput::print_output(
            EmptyContext,
            &FunctionDef {
                mods: NoOpSeq,
                name: Str("hello_world"),
                args: CombinedSeq(
                    SingularSeq(FunctionParam(Str("var1"), Str("Type")).with_attributes(
                        CombinedSeq(SingularSeq(MustUse), SingularSeq(Str("attr2"))),
                    )),
                    SingularSeq(FunctionParam(Str("var2"), Str("&'static Type2"))),
                ),
                return_type: Str("()"),
                where_conds: NoOpSeq,
                body: FunctionBodyDeclare,
            },
        );
    assert_eq!(
        "fn hello_world(#[must_use] #[attr2] var1: Type, var2: &'static Type2) -> ();\n\n",
        string
    );
}

#[test]
fn turbofish() {
    let string = InMemoryOutput::print_output(
        EmptyContext,
        &Turbofish(Str("my_method"), StrArrSeq(&["V1", "V2"])),
    );
    assert_eq!("my_method::<V1, V2>", string);
    let string = InMemoryOutput::print_output(EmptyContext, &Turbofish(Str("my_method"), NoOpSeq));
    assert_eq!("my_method", string);
}

#[test]
fn array_from_elements() {
    let string = InMemoryOutput::print_output(
        EmptyContext,
        &ArrayFromElements(StrArrSeq(&["1", "2", "-4"])),
    );
    assert_eq!("[1, 2, -4]", string);
}

#[test]
fn no_mangle_attr_2021() {
    let string = InMemoryOutput::print_output(SingularContext(Edition::Rust2021), &NoMangle);
    assert_eq!(string, "no_mangle");
}

#[test]
fn no_mangle_attr_2024() {
    let string = InMemoryOutput::print_output(SingularContext(Edition::Rust2024), &NoMangle);
    assert_eq!(string, "unsafe(no_mangle)");
}

#[test]
fn dereference_raw_ptr_field() {
    let string = InMemoryOutput::print_output(
        EmptyContext,
        &RefOf(Dereference(MemberAccess(Str("my_struct"), Str("my_ptr")))),
    );
    assert_eq!("&*my_struct.my_ptr", string);
}

#[test]
fn array_init() {
    let array_init = ArrayInit(Str("None"), Str("5"));
    let string = InMemoryOutput::print_output(EmptyContext, &array_init);
    assert_eq!("[None; 5]", string);
}

#[test]
fn trait_with_unsafe_impl() {
    let trait_impl = TraitImpl {
        mods: SingularSeq(ModUnsafe),
        type_variables: SingularSeq(Str("T")),
        the_trait: Str("Debug"),
        receiver: Parameterized(Str("MyType"), SingularSeq(Str("T"))),
        where_conds: NoOpSeq,
        body: NoOp,
    };
    let string = InMemoryOutput::print_output(EmptyContext, &trait_impl);
    assert_eq!(string, "unsafe impl<T> Debug for MyType<T> {\n}\n\n");
}

#[test]
fn named_tuple() {
    let string = InMemoryOutput::print_output(
        EmptyContext,
        &NamedTuple {
            name: Str("MyType"),
            args: StrArrSeq(&["V1", "V2"]),
        },
    );
    assert_eq!(string, "MyType(V1, V2)");
    let string = InMemoryOutput::print_output(
        EmptyContext,
        &NamedTuple {
            name: Str("MyType"),
            args: NoOpSeq,
        },
    );
    assert_eq!(string, "MyType");
}

#[test]
fn anon_tuple() {
    let string = InMemoryOutput::print_output(EmptyContext, &AnonTuple(StrArrSeq(&["V1", "V2"])));
    assert_eq!(string, "(V1, V2)");
    let string = InMemoryOutput::print_output(EmptyContext, &AnonTuple(NoOpSeq));
    assert_eq!(string, "()");
}

#[test]
fn bounded_type_var() {
    let type_var = BoundedTypeVar(
        Str("MyType"),
        CombinedSeq(SingularSeq(Str("B1")), SingularSeq(Str("B2"))),
    );
    let string = InMemoryOutput::print_output(EmptyContext, &type_var);
    assert_eq!(string, "MyType: B1 + B2");
}