1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
use proc_macro::TokenStream;
use syn::spanned::Spanned;

pub(super) fn parse_kernel_fn(tokens: TokenStream) -> syn::ItemFn {
    let func: syn::ItemFn = syn::parse(tokens).unwrap_or_else(|err| {
        abort_call_site!(
            "#[kernel(...)] must be wrapped around a function: {:?}",
            err
        )
    });

    if !matches!(func.vis, syn::Visibility::Public(_)) {
        abort!(func.vis.span(), "Kernel function must be public.");
    }

    if func.sig.constness.is_some() {
        abort!(
            func.sig.constness.span(),
            "Kernel function must not be const."
        );
    }

    if func.sig.asyncness.is_some() {
        abort!(
            func.sig.asyncness.span(),
            "Kernel function must not be async."
        );
    }

    if func.sig.abi.is_some() {
        abort!(
            func.sig.abi.span(),
            "Kernel function must not have an explicit ABI."
        );
    }

    if func.sig.variadic.is_some() {
        abort!(
            func.sig.variadic.span(),
            "Kernel function must not be variadic."
        );
    }

    for param in &func.sig.inputs {
        if let syn::FnArg::Receiver(receiver) = param {
            abort!(receiver.span(), "Kernel function must not have a receiver.");
        }
    }

    if func.sig.inputs.len() > 12 {
        emit_warning!(
            func.sig.inputs.span(),
            "Kernel function has too many arguments, {} were found but at most 12 are supported.",
            func.sig.inputs.len()
        );
    }

    match &func.sig.output {
        syn::ReturnType::Default => (),
        syn::ReturnType::Type(_, box syn::Type::Tuple(tuple)) if tuple.elems.is_empty() => (),
        syn::ReturnType::Type(_, non_unit_type) => abort!(
            non_unit_type.span(),
            "Kernel function must return the unit type."
        ),
    };

    if let Some(r#where) = &func.sig.generics.where_clause {
        abort!(
            r#where.span(),
            "Kernel function must not have a where clause, use type generic bounds instead."
        );
    }

    func
}