darkfi_derive/
lib.rs

1/* This file is part of DarkFi (https://dark.fi)
2 *
3 * Copyright (C) 2020-2025 Dyne.org foundation
4 *
5 * This program is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU Affero General Public License as
7 * published by the Free Software Foundation, either version 3 of the
8 * License, or (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 * GNU Affero General Public License for more details.
14 *
15 * You should have received a copy of the GNU Affero General Public License
16 * along with this program.  If not, see <https://www.gnu.org/licenses/>.
17 */
18
19extern crate proc_macro;
20use proc_macro::TokenStream;
21use proc_macro2::{Span, TokenStream as TokenStream2};
22use proc_macro_crate::{crate_name, FoundCrate};
23use quote::quote;
24use syn::{Ident, ItemEnum, ItemStruct, ItemUnion};
25
26#[cfg(feature = "async")]
27use darkfi_derive_internal::{async_enum_de, async_enum_ser, async_struct_de, async_struct_ser};
28
29use darkfi_derive_internal::{enum_de, enum_ser, struct_de, struct_ser};
30
31#[proc_macro_derive(SerialEncodable, attributes(skip_serialize))]
32pub fn darkfi_serialize(input: TokenStream) -> TokenStream {
33    let found_crate = crate_name("darkfi-serial").expect("darkfi-serial is found in Cargo.toml");
34
35    let found_crate = match found_crate {
36        FoundCrate::Name(name) => name,
37        FoundCrate::Itself => "crate".to_string(),
38    };
39
40    let cratename = Ident::new(&found_crate, Span::call_site());
41
42    let res: syn::Result<TokenStream2> = if let Ok(input) = syn::parse::<ItemStruct>(input.clone())
43    {
44        let sync_tokens = struct_ser(&input, cratename.clone()).unwrap();
45        #[cfg(feature = "async")]
46        let async_tokens = async_struct_ser(&input, cratename).unwrap();
47        #[cfg(not(feature = "async"))]
48        let async_tokens = quote! {};
49
50        Ok(quote! {
51            #sync_tokens
52            #async_tokens
53        })
54    } else if let Ok(input) = syn::parse::<ItemEnum>(input.clone()) {
55        let sync_tokens = enum_ser(&input, cratename.clone()).unwrap();
56        #[cfg(feature = "async")]
57        let async_tokens = async_enum_ser(&input, cratename).unwrap();
58        #[cfg(not(feature = "async"))]
59        let async_tokens = quote! {};
60
61        Ok(quote! {
62            #sync_tokens
63            #async_tokens
64        })
65    } else if let Ok(_input) = syn::parse::<ItemUnion>(input) {
66        todo!()
67    } else {
68        // Derive macros can only be defined on structs, enums, and unions.
69        unreachable!()
70    };
71
72    TokenStream::from(res.unwrap_or_else(|err| err.to_compile_error()))
73}
74
75#[proc_macro_derive(SerialDecodable, attributes(skip_serialize))]
76pub fn darkfi_deserialize(input: TokenStream) -> TokenStream {
77    let found_crate = crate_name("darkfi-serial").expect("darkfi-serial is found in Cargo.toml");
78
79    let found_crate = match found_crate {
80        FoundCrate::Name(name) => name,
81        FoundCrate::Itself => "crate".to_string(),
82    };
83
84    let cratename = Ident::new(&found_crate, Span::call_site());
85
86    let res: syn::Result<TokenStream2> = if let Ok(input) = syn::parse::<ItemStruct>(input.clone())
87    {
88        let sync_tokens = struct_de(&input, cratename.clone()).unwrap();
89        #[cfg(feature = "async")]
90        let async_tokens = async_struct_de(&input, cratename).unwrap();
91        #[cfg(not(feature = "async"))]
92        let async_tokens = quote! {};
93
94        Ok(quote! {
95            #sync_tokens
96            #async_tokens
97        })
98    } else if let Ok(input) = syn::parse::<ItemEnum>(input.clone()) {
99        let sync_tokens = enum_de(&input, cratename.clone()).unwrap();
100        #[cfg(feature = "async")]
101        let async_tokens = async_enum_de(&input, cratename).unwrap();
102        #[cfg(not(feature = "async"))]
103        let async_tokens = quote! {};
104
105        Ok(quote! {
106            #sync_tokens
107            #async_tokens
108        })
109    } else if let Ok(_input) = syn::parse::<ItemUnion>(input) {
110        todo!()
111    } else {
112        // Derive macros can only be defined on structs, enums, and unions.
113        unreachable!()
114    };
115
116    TokenStream::from(res.unwrap_or_else(|err| err.to_compile_error()))
117}