serde_bindgen_core_derive/
lib.rs

1// This file is part of the serde-bindgen-core libraries
2// Copyright (C) 2022  Altronix Corp. <thomas.chiantia@gmail.com>
3//
4// This program is free software: you can redistribute it and/or modify
5// it under the terms of the GNU General Public License as published by
6// the Free Software Foundation, either version 3 of the License, or
7// (at your option) any later version.
8//
9// This program is distributed in the hope that it will be useful,
10// but WITHOUT ANY WARRANTY; without even the implied warranty of
11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12// GNU General Public License for more details.
13//
14// You should have received a copy of the GNU General Public License
15// along with this program.  If not, see <https://www.gnu.org/licenses/>.
16
17// @author Thomas Chiantia <thomas.chiantia@gmail.com>
18// @date 2022
19
20#[cfg(test)]
21mod tests;
22
23mod attributes;
24mod context;
25mod field;
26mod keyword;
27mod path;
28mod utils;
29
30use attributes::ContainerAttributes;
31use context::Context;
32use proc_macro::TokenStream;
33use quote::quote;
34use std::borrow::Cow;
35use syn::parse_macro_input;
36
37#[proc_macro_attribute]
38pub fn binding(attr: TokenStream, item: TokenStream) -> TokenStream {
39    let container_attributes = parse_macro_input!(attr as ContainerAttributes);
40    let prefix: Option<Cow<str>> = container_attributes
41        .seek_val("prefix")
42        .map(|lit| Cow::Owned(lit.value()));
43    let rename_all = container_attributes
44        .seek_val("rename_all")
45        .map(|lit| {
46            let val = lit.value();
47            Some(quote! {#[serde(rename_all= #val)]})
48        })
49        .unwrap_or(None);
50
51    // Parse the callers decorated struct
52    let ctx: Context = parse_macro_input!(item);
53
54    // create a type alias
55    let (ident_original, ident_borrowed, _ident_owned) = ctx.path.split_self_for_impl();
56
57    // create an "owned" version of the struct. (no references)
58    let owned = ctx.clone().into_owned();
59
60    // create a const FOO: usize = max_len block
61    let impl_weight = ctx.impl_weight();
62
63    // create impl Default block
64    let impl_default = ctx.impl_default();
65
66    // create impl From block
67    let impl_from_owned = ctx.impl_from_owned();
68
69    // create impl From block
70    let impl_from_ref = ctx.impl_from_ref();
71
72    // create binding for copy function
73    let binding_copy = ctx.binding_copy(prefix.clone());
74
75    // create binding for init function
76    let binding_init = ctx.binding_init(prefix.clone());
77
78    // create binding for parse function
79    let binding_parse = ctx.binding_parse(prefix.clone());
80
81    // create binding for parse function
82    let binding_print = ctx.binding_print(prefix.clone());
83
84    // create binding for parse function
85    let binding_print_owned = ctx.binding_print_owned(prefix.clone());
86
87    // render all the new items
88    let quoted = quote! {
89        #[no_mangle]
90        #impl_weight
91        #[no_mangle]
92        pub type #ident_borrowed = #ident_original;
93        #[repr(C)]
94        #[derive(serde::Deserialize)]
95        #[derive(serde::Serialize)]
96        #[serde(crate="self::serde")]
97        #rename_all
98        #ctx
99        #[repr(C)]
100        #owned
101        #impl_default
102        #impl_from_owned
103        #impl_from_ref
104        #binding_copy
105        #binding_init
106        #binding_parse
107        #binding_print
108        #binding_print_owned
109    };
110    proc_macro::TokenStream::from(quoted)
111}