1use proc_macro::TokenStream;
2use proc_macro_error2::{abort, abort_call_site};
3use quote::quote;
4use syn::{parse_macro_input, Fields, ItemStruct};
5
6pub(crate) fn expand(args: TokenStream, item: TokenStream) -> TokenStream {
7 if !args.is_empty() {
8 abort_call_site!("`#[global_logger]` attribute takes no arguments")
9 }
10
11 let strukt: ItemStruct = parse_macro_input!(item as ItemStruct);
12
13 validate(&strukt);
14
15 codegen(&strukt)
16}
17
18fn validate(strukt: &ItemStruct) {
19 let is_unit_struct: bool = matches!(strukt.fields, Fields::Unit);
20
21 if !strukt.generics.params.is_empty()
22 || strukt.generics.where_clause.is_some()
23 || !is_unit_struct
24 {
25 abort!(
26 strukt,
27 "struct must be a non-generic unit struct (e.g. `struct S;`)"
28 );
29 }
30}
31
32fn codegen(strukt: &ItemStruct) -> TokenStream {
33 let attrs = &strukt.attrs;
34 let ident = &strukt.ident;
35 let vis = &strukt.vis;
36
37 quote!(
38 #(#attrs)*
39 #vis struct #ident;
40
41 #[inline(never)]
42 #[no_mangle]
43 unsafe fn _defmt_acquire() {
44 <#ident as defmt::Logger>::acquire()
45 }
46
47 #[inline(never)]
48 #[no_mangle]
49 unsafe fn _defmt_flush() {
50 <#ident as defmt::Logger>::flush()
51 }
52
53 #[inline(never)]
54 #[no_mangle]
55 unsafe fn _defmt_release() {
56 <#ident as defmt::Logger>::release()
57 }
58
59 #[inline(never)]
60 #[no_mangle]
61 unsafe fn _defmt_write(bytes: &[u8]) {
62 <#ident as defmt::Logger>::write(bytes)
63 }
64 )
65 .into()
66}
67