oasis_borsh_derive/
lib.rs1extern crate proc_macro;
2
3use oasis_borsh_derive_internal::*;
4use proc_macro::TokenStream;
5use quote::{quote, format_ident};
6use syn::{parse_macro_input, Ident, ItemEnum, ItemStruct, ItemUnion, LitInt, Token};
7
8#[proc_macro_derive(BorshSerialize, attributes(borsh_skip))]
9pub fn borsh_serialize(input: TokenStream) -> TokenStream {
10 let res = if let Ok(input) = syn::parse::<ItemStruct>(input.clone()) {
11 struct_ser(&input)
12 } else if let Ok(input) = syn::parse::<ItemEnum>(input.clone()) {
13 enum_ser(&input)
14 } else if let Ok(input) = syn::parse::<ItemUnion>(input.clone()) {
15 union_ser(&input)
16 } else {
17 unreachable!()
19 };
20 TokenStream::from(match res {
21 Ok(res) => res,
22 Err(err) => err.to_compile_error(),
23 })
24}
25
26#[proc_macro_derive(BorshDeserialize, attributes(borsh_skip, borsh_init))]
27pub fn borsh_deserialize(input: TokenStream) -> TokenStream {
28 let res = if let Ok(input) = syn::parse::<ItemStruct>(input.clone()) {
29 struct_de(&input)
30 } else if let Ok(input) = syn::parse::<ItemEnum>(input.clone()) {
31 enum_de(&input)
32 } else if let Ok(input) = syn::parse::<ItemUnion>(input.clone()) {
33 union_de(&input)
34 } else {
35 unreachable!()
37 };
38 TokenStream::from(match res {
39 Ok(res) => res,
40 Err(err) => err.to_compile_error(),
41 })
42}
43
44struct SeqMacroSpec {
45 mac_ident: Ident,
46 prefix: Option<Ident>,
47 lengths: Vec<usize>,
48}
49
50impl syn::parse::Parse for SeqMacroSpec {
51 fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
52 let mac_ident = input.parse()?;
53 input.parse::<Token![=>]>()?;
54
55 let prefix = input.parse::<Option<Ident>>()?;
56 if prefix.is_some() {
57 input.parse::<Token![::]>()?;
58 }
59
60 let seq_lengths;
61 syn::parenthesized!(seq_lengths in input);
62 let punctuated_lengths: syn::punctuated::Punctuated<LitInt, syn::parse::Nothing> =
63 seq_lengths.parse_terminated(LitInt::parse)?;
64 let lengths = punctuated_lengths
65 .iter()
66 .map(|l| l.base10_parse::<usize>())
67 .collect::<Result<Vec<_>, _>>()?;
68
69 Ok(SeqMacroSpec {
70 mac_ident,
71 prefix,
72 lengths,
73 })
74 }
75}
76
77#[proc_macro]
78#[doc(hidden)]
79pub fn _gen_seq_macro(input: TokenStream) -> TokenStream {
80 let SeqMacroSpec {
81 mac_ident,
82 prefix,
83 lengths,
84 } = parse_macro_input!(input as SeqMacroSpec);
85 let seqs = lengths.iter().copied().map(|len| {
86 (0..len)
87 .map(|i| {
88 if let Some(prefix) = &prefix {
89 let seq_ident = format_ident!("{}{}", prefix, i);
90 quote!(#seq_ident)
91 } else {
92 let seq_lit = proc_macro2::Literal::usize_unsuffixed(i);
93 quote!(#seq_lit)
94 }
95 })
96 .collect::<Vec<_>>()
97 });
98 let length_lits = lengths
99 .iter()
100 .map(|&i| proc_macro2::Literal::usize_unsuffixed(i));
101 let ts = TokenStream::from(quote! {
102 #mac_ident!(#(#length_lits => ( #(#seqs)* ))*);
103 });
104 ts
105}