embassy_agb_macros/
lib.rs1use proc_macro::TokenStream;
2use quote::quote;
3use syn::{parse_macro_input, ItemFn, ReturnType, Type};
4
5#[proc_macro_attribute]
30pub fn main(_args: TokenStream, input: TokenStream) -> TokenStream {
31 let f = parse_macro_input!(input as ItemFn);
32
33 if f.sig.inputs.len() != 1 {
35 return quote! {
36 compile_error!("embassy_agb::main function must take exactly one parameter: Spawner");
37 }
38 .into();
39 }
40
41 let returns_never =
43 matches!(f.sig.output, ReturnType::Type(_, ref ty) if matches!(**ty, Type::Never(_)));
44
45 let fn_name = &f.sig.ident;
46 let fn_args = &f.sig.inputs;
47 let fn_body = &f.block;
48 let fn_attrs = &f.attrs;
49
50 let spawner_param = match f.sig.inputs.first() {
52 Some(syn::FnArg::Typed(pat_type)) => match &*pat_type.pat {
53 syn::Pat::Ident(ident) => &ident.ident,
54 _ => panic!("Expected spawner parameter to be a simple identifier"),
55 },
56 _ => panic!("Expected spawner parameter"),
57 };
58
59 let result = if returns_never {
60 quote! {
62 #[::embassy_agb::agb::entry]
63 fn agb_main(gba: ::embassy_agb::agb::Gba) -> ! {
64 unsafe {
66 ::embassy_agb::_internal::set_agb_instance(gba);
67 }
68
69 unsafe fn __make_static<T>(t: &mut T) -> &'static mut T {
70 ::core::mem::transmute(t)
71 }
72
73 let mut executor = ::embassy_agb::Executor::new();
74 let executor = unsafe { __make_static(&mut executor) };
75 executor.run(|spawner| {
76 spawner.must_spawn(main_task(spawner));
77 });
78 }
79
80 #[::embassy_executor::task]
81 async fn main_task(#fn_args) -> ! {
82 #(#fn_attrs)*
83 async fn #fn_name(#fn_args) -> ! #fn_body
84 #fn_name(#spawner_param).await
85 }
86 }
87 } else {
88 quote! {
90 #[::embassy_agb::agb::entry]
91 fn agb_main(gba: ::embassy_agb::agb::Gba) -> ! {
92 unsafe {
94 ::embassy_agb::_internal::set_agb_instance(gba);
95 }
96
97 unsafe fn __make_static<T>(t: &mut T) -> &'static mut T {
98 ::core::mem::transmute(t)
99 }
100
101 let mut executor = ::embassy_agb::Executor::new();
102 let executor = unsafe { __make_static(&mut executor) };
103 executor.run(|spawner| {
104 spawner.must_spawn(main_task(spawner));
105 });
106 }
107
108 #[::embassy_executor::task]
109 async fn main_task(#fn_args) {
110 #(#fn_attrs)*
111 async fn #fn_name(#fn_args) #fn_body
112 #fn_name(#spawner_param).await;
113
114 loop {
116 ::embassy_agb::agb::halt();
117 }
118 }
119 }
120 };
121
122 result.into()
123}
124
125#[proc_macro_attribute]
129pub fn task(args: TokenStream, input: TokenStream) -> TokenStream {
130 let args = proc_macro2::TokenStream::from(args);
132 let input = proc_macro2::TokenStream::from(input);
133
134 quote! {
135 #[::embassy_executor::task(#args)]
136 #input
137 }
138 .into()
139}