You are an expert in writing code in many different languages. Your goal is to perform code completion for the following code, keeping in mind the rest of the code and the file meta data.
    Metadata details:
    filename: async_dispatchers.rs
    path of file: ./repos/rtic/rtic-macros/src/codegen
    
    the code of the file until where you have to start completion: use crate::syntax::ast::App;
use crate::{
    analyze::Analysis,
    codegen::{
        bindings::{async_entry, handler_config, interrupt_entry, interrupt_exit},
        util,
    },
};
use proc_macro2::TokenStream as TokenStream2;
use quote::quote;

/// Generates task dispatchers
pub fn codegen(app: &App, analysis: &Analysis) -> TokenStream2 {
    let mut items = vec![];

    let interrupts = &analysis.interrupts;

    // Generate executor definition and priority in global scope
    for (name, _) in app.software_tasks.iter() {
        let exec_name = util::internal_task_ident(name, "EXEC");

        items.push(quote!(
            #[allow(non_upper_case_globals)]
            static #exec_name: rtic::export::executor::AsyncTaskExecutorPtr =
                rtic::export::executor::AsyncTaskExecutorPtr::new();
        ));
    }

    for (&level, channel) in &analysis.channels {
        let mut stmts = vec![];

        let dispatcher_name = if level > 0 {
            util::suffixed(&interrupts.get(&level).expect("UNREACHABLE").0.to_string())
        } else {
            util::zero_prio_dispatcher_ident()
        };

        let pend_interrupt = if level > 0 {
  
    
pub fn codegen(app: &App, analysis: &Analysis) -> TokenStream2 {
    let mut items = vec![];

    let interrupts = &analysis.interrupts;

    // Generate executor definition and priority in global scope
    for (name, _) in app.software_tasks.iter() {
        let exec_name = util::internal_task_ident(name, "EXEC");

        items.push(quote!(
            #[allow(non_upper_case_globals)]
            static #exec_name: rtic::export::executor::AsyncTaskExecutorPtr =
                rtic::export::executor::AsyncTaskExecutorPtr::new();
        ));
    }

    for (&level, channel) in &analysis.channels {
        let mut stmts = vec![];

        let dispatcher_name = if level > 0 {
            util::suffixed(&interrupts.get(&level).expect("UNREACHABLE").0.to_string())
        } else {
            util::zero_prio_dispatcher_ident()
        };

        let pend_interrupt = if level > 0 {
            let device = &app.args.device;
            let enum_ = util::interrupt_ident();

            quote!(rtic::export::pend(#device::#enum_::#dispatcher_name);)
        } else {
            // For 0 priority tasks we don't need to pend anything
            quote!()
        };

        for name in channel.tasks.iter() {
            let exec_name = util::internal_task_ident(name, "EXEC");
            let from_ptr_n_args =
                util::from_ptr_n_args_ident(app.software_tasks[name].inputs.len());

            // TODO: Fix cfg
            // let task = &app.software_tasks[name];
            // let cfgs = &task.cfgs;

            stmts.push(quote!(
                let exec = rtic::export::executor::AsyncTaskExecutor::#from_ptr_n_args(#name, &#exec_name);
                exec.poll(|| {
                    let exec = rtic::export::executor::AsyncTaskExecutor::#from_ptr_n_args(#name, &#exec_name);
                    exec.set_pending();
                    #pend_interrupt
                });
            ));
        }

        if level > 0 {
            let doc = format!("Interrupt handler to dispatch async tasks at priority {level}");
            let attribute = &interrupts.get(&level).expect("UNREACHABLE").1.attrs;
            let entry_stmts = interrupt_entry(app, analysis);
            let exit_stmts = interrupt_exit(app, analysis);
            let async_entry_stmts = async_entry(app, analysis, dispatcher_name.clone());
            let config = handler_config(app, analysis, dispatcher_name.clone());
            items.push(quote!(
                #[allow(non_snake_case)]
                #[doc = #doc]
                #[no_mangle]
                #(#attribute)*
                #(#config)*
                unsafe fn #dispatcher_name() {
                    #(#entry_stmts)*
                    #(#async_entry_stmts)*

                    /// The priority of this interrupt handler
                    const PRIORITY: u8 = #level;

                    rtic::export::run(PRIORITY, || {
                        #(#stmts)*
                    });

                    #(#exit_stmts)*
                }
            ));
        } else {
            items.push(quote!(
                #[allow(non_snake_case)]
                unsafe fn #dispatcher_name() -> ! {
                    loop {
                        #(#stmts)*
                    }
                }
            ));
        }
    }

    quote!(#(#items)*)
}