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 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}