borsh_derive/internals/serialize/
mod.rs

1use proc_macro2::{Span, TokenStream as TokenStream2};
2use quote::quote;
3use std::convert::TryFrom;
4use syn::{Expr, ExprPath, Generics, Ident, Index, Path};
5
6use super::generics;
7
8pub mod enums;
9pub mod structs;
10pub mod unions;
11
12struct GenericsOutput {
13    overrides: Vec<syn::WherePredicate>,
14    serialize_visitor: generics::FindTyParams,
15}
16
17impl GenericsOutput {
18    fn new(generics: &Generics) -> Self {
19        Self {
20            overrides: vec![],
21            serialize_visitor: generics::FindTyParams::new(generics),
22        }
23    }
24    fn extend(self, where_clause: &mut syn::WhereClause, cratename: &Path) {
25        let trait_path: Path = syn::parse2(quote! { #cratename::ser::BorshSerialize }).unwrap();
26        let predicates =
27            generics::compute_predicates(self.serialize_visitor.process_for_bounds(), &trait_path);
28        where_clause.predicates.extend(predicates);
29        where_clause.predicates.extend(self.overrides);
30    }
31}
32
33pub enum FieldId {
34    Struct(Ident),
35    StructUnnamed(Index),
36    Enum(Ident),
37    EnumUnnamed(Index),
38}
39
40impl FieldId {
41    fn index(field_idx: usize) -> syn::Result<Index> {
42        let index = u32::try_from(field_idx).map_err(|err| {
43            syn::Error::new(
44                Span::call_site(),
45                format!("up to 2^32 fields are supported {}", err),
46            )
47        })?;
48        Ok(Index {
49            index,
50            span: Span::call_site(),
51        })
52    }
53    pub fn new_struct_unnamed(field_idx: usize) -> syn::Result<Self> {
54        let index = Self::index(field_idx)?;
55        let result = Self::StructUnnamed(index);
56        Ok(result)
57    }
58    pub fn new_enum_unnamed(field_idx: usize) -> syn::Result<Self> {
59        let index = Self::index(field_idx)?;
60        let result = Self::EnumUnnamed(index);
61        Ok(result)
62    }
63}
64
65impl FieldId {
66    fn serialize_arg(&self) -> Expr {
67        match self {
68            Self::Struct(name) => syn::parse2(quote! { &self.#name }).unwrap(),
69            Self::StructUnnamed(index) => syn::parse2(quote! { &self.#index }).unwrap(),
70            Self::Enum(name) => syn::parse2(quote! { #name }).unwrap(),
71            Self::EnumUnnamed(ind) => {
72                let field = Ident::new(&format!("id{}", ind.index), Span::mixed_site());
73                syn::parse2(quote! { #field }).unwrap()
74            }
75        }
76    }
77    /// function which computes derive output [proc_macro2::TokenStream]
78    /// of code, which serializes single field
79    pub fn serialize_output(
80        &self,
81        cratename: &Path,
82        serialize_with: Option<ExprPath>,
83    ) -> TokenStream2 {
84        let arg: Expr = self.serialize_arg();
85        if let Some(func) = serialize_with {
86            quote! { #func(#arg, writer)?; }
87        } else {
88            quote! { #cratename::BorshSerialize::serialize(#arg, writer)?; }
89        }
90    }
91    pub fn enum_variant_header(&self, skipped: bool) -> Option<TokenStream2> {
92        match self {
93            Self::Struct(..) | Self::StructUnnamed(..) => unreachable!("no variant header"),
94            Self::Enum(name) => (!skipped).then_some(quote! { #name, }),
95            Self::EnumUnnamed(index) => {
96                let field_ident = if skipped {
97                    Ident::new(&format!("_id{}", index.index), Span::mixed_site())
98                } else {
99                    Ident::new(&format!("id{}", index.index), Span::mixed_site())
100                };
101                Some(quote! { #field_ident, })
102            }
103        }
104    }
105}