postcard_bindgen_derive/
lib.rs

1use derive_enum::derive_enum;
2use derive_struct::derive_struct;
3use proc_macro2::TokenStream;
4use quote::quote;
5use serde_derive_internals::{ast, Ctxt, Derive};
6use syn::DeriveInput;
7
8mod derive_enum;
9mod derive_struct;
10
11#[proc_macro_derive(PostcardBindings)]
12pub fn postcard_bindings(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
13    derive_js_implementation(input).into()
14}
15
16fn derive_js_implementation(input: proc_macro::TokenStream) -> TokenStream {
17    let input: DeriveInput = syn::parse(input).unwrap();
18
19    let cx = Ctxt::new();
20    let container = ast::Container::from_ast(&cx, &input, Derive::Serialize).unwrap();
21
22    let body = match container.data {
23        ast::Data::Enum(variants) => derive_enum(container.ident.to_owned(), variants),
24        ast::Data::Struct(style, fields) => {
25            derive_struct(style, container.ident.to_owned(), fields)
26        }
27    };
28
29    let ident = container.ident;
30    let generics = container.generics;
31    let container_name = ident.to_string();
32
33    let expanded = if cfg!(feature = "expanding") {
34        quote!(
35            const _: () = {
36                #[allow(unused_extern_crates, clippy::useless_attribute)]
37                extern crate postcard_bindgen as _pb;
38                impl #generics _pb::__private::JsBindings for #ident #generics {
39                    fn create_bindings(reg: &mut _pb::__private::BindingsRegistry) {
40                        #body
41                    }
42                }
43
44                impl #generics _pb::__private::GenBinding for #ident #generics {
45                    fn get_type() -> _pb::__private::ValueType {
46                        _pb::__private::ValueType::Object(_pb::__private::ObjectMeta {
47                            name: #container_name.into(),
48                            path: _pb::__private::Path::new(module_path!(), "::"),
49                        })
50                    }
51                }
52            };
53        )
54    } else {
55        TokenStream::new()
56    };
57
58    cx.check().unwrap();
59
60    expanded
61}