darkfi_derive_internal/
lib.rs

1/* This file is part of DarkFi (https://dark.fi)
2 *
3 * Copyright (C) 2020-2026 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
19//! Derive (de)serialization for enums and structs, see src/serial/derive
20use std::collections::HashMap;
21
22use proc_macro2::{Ident, TokenStream};
23use quote::quote;
24use syn::{punctuated::Punctuated, token::Comma, Attribute, Path, Variant, WherePredicate};
25
26mod sync_derive;
27pub use sync_derive::{enum_de, enum_ser, struct_de, struct_ser};
28
29#[cfg(feature = "async")]
30mod async_derive;
31#[cfg(feature = "async")]
32pub use async_derive::{async_enum_de, async_enum_ser, async_struct_de, async_struct_ser};
33
34struct VariantParts {
35    where_predicates: Vec<WherePredicate>,
36    variant_header: TokenStream,
37    variant_body: TokenStream,
38    variant_idx_body: TokenStream,
39}
40
41/// Calculates the discriminant that will be assigned by the compiler.
42/// See: <https://doc.rust-lang.org/reference/items/enumerations.html#assigning-discriminant-values>
43fn discriminant_map(variants: &Punctuated<Variant, Comma>) -> HashMap<Ident, TokenStream> {
44    let mut map = HashMap::new();
45
46    let mut next_discriminant_if_not_specified = quote! {0};
47
48    for variant in variants {
49        let this_discriminant = variant
50            .discriminant
51            .clone()
52            .map_or_else(|| quote! { #next_discriminant_if_not_specified }, |(_, e)| quote! { #e });
53
54        next_discriminant_if_not_specified = quote! { #this_discriminant + 1 };
55        map.insert(variant.ident.clone(), this_discriminant);
56    }
57
58    map
59}
60
61pub fn contains_skip(attrs: &[Attribute]) -> bool {
62    attrs.iter().any(|attr| attr.path().is_ident("skip_serialize"))
63}
64
65pub fn contains_initialize_with(attrs: &[Attribute]) -> Option<Path> {
66    for attr in attrs.iter() {
67        if attr.path().is_ident("init_serialize") {
68            let mut res = None;
69            let _ = attr.parse_nested_meta(|meta| {
70                res = Some(meta.path);
71                Ok(())
72            });
73            return res
74        }
75    }
76
77    None
78}