1 | use proc_macro::TokenStream; |
2 | use proc_macro_error2::{abort, abort_call_site}; |
3 | use quote::quote; |
4 | use syn::{parse_macro_input, Fields, ItemStruct}; |
5 | |
6 | pub(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 | |
18 | fn 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 | |
32 | fn 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 | |