1use proc_macro2::TokenStream;
2use quote::quote;
3use syn::{parse_macro_input, Attribute, DeriveInput, Error, Fields, Meta, NestedMeta};
4
5mod read;
6mod write;
7
8#[proc_macro_derive(WriteCbor, attributes(cbor))]
9pub fn derive_write(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
10 let input = parse_macro_input!(input as DeriveInput);
11 let name = input.ident;
12 let (g_impl, g_type, g_where) = input.generics.split_for_impl();
13
14 let code = match write::code_write(input.data, input.attrs) {
15 Ok(code) => code,
16 Err(e) => {
17 return e
18 .into_iter()
19 .map(Error::into_compile_error)
20 .collect::<TokenStream>()
21 .into()
22 }
23 };
24
25 let ret = quote! {
26 impl #g_impl ::cbor_data::codec::WriteCbor for #name #g_type #g_where {
27 fn write_cbor<W: ::cbor_data::Writer>(&self, w: W) -> W::Output {
28 #code
29 }
30 }
31 };
32 ret.into()
33}
34
35#[proc_macro_derive(ReadCbor, attributes(cbor))]
36pub fn derive_read(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
37 let input = parse_macro_input!(input as DeriveInput);
38 let name = input.ident;
39 let (g_impl, g_type, g_where) = input.generics.split_for_impl();
40
41 let code = match read::code_read(input.data, input.attrs) {
42 Ok(code) => code,
43 Err(e) => {
44 return e
45 .into_iter()
46 .map(Error::into_compile_error)
47 .collect::<TokenStream>()
48 .into()
49 }
50 };
51
52 let name_string = name.to_string();
53 let ret = quote! {
54 impl #g_impl ::cbor_data::codec::ReadCbor for #name #g_type #g_where {
55 fn fmt(f: &mut impl ::std::fmt::Write) -> ::std::fmt::Result {
56 write!(f, #name_string)
57 }
58
59 fn read_cbor_impl(cbor: &::cbor_data::Cbor) -> ::cbor_data::codec::Result<Self>
60 where
61 Self: Sized,
62 {
63 #code
64 }
65 }
66 };
67 ret.into()
68}
69
70fn is_one_tuple(f: &Fields) -> bool {
71 match f {
72 Fields::Unnamed(f) => f.unnamed.len() == 1,
73 _ => false,
74 }
75}
76
77fn is_transparent(a: &&Attribute) -> bool {
78 if let Ok(Meta::List(l)) = a.parse_meta() {
79 l.path.is_ident("cbor")
80 && l.nested
81 .iter()
82 .any(|m| matches!(m, NestedMeta::Meta(Meta::Path(p)) if p.is_ident("transparent")))
83 } else {
84 false
85 }
86}