1#![recursion_limit = "128"]
2#![cfg_attr(
3 feature = "force_exhaustive_checks",
4 feature(non_exhaustive_omitted_patterns_lint)
5)]
6#![allow(clippy::needless_lifetimes)]
7
8extern crate proc_macro;
9use proc_macro::TokenStream;
10#[cfg(feature = "schema")]
11use proc_macro2::Span;
12use syn::{DeriveInput, Error, ItemEnum, ItemStruct, ItemUnion, Path};
13
14mod internals;
16
17use crate::internals::attributes::item;
18
19#[cfg(feature = "schema")]
20use internals::schema;
21use internals::{cratename, deserialize, serialize};
22
23fn check_attrs_get_cratename(input: &TokenStream) -> Result<Path, Error> {
24 let input = input.clone();
25
26 let derive_input = syn::parse::<DeriveInput>(input)?;
27
28 item::check_attributes(&derive_input)?;
29
30 cratename::get(&derive_input.attrs)
31}
32
33#[proc_macro_derive(BorshSerialize, attributes(borsh))]
37pub fn borsh_serialize(input: TokenStream) -> TokenStream {
38 let cratename = match check_attrs_get_cratename(&input) {
39 Ok(cratename) => cratename,
40 Err(err) => {
41 return err.to_compile_error().into();
42 }
43 };
44
45 let res = if let Ok(input) = syn::parse::<ItemStruct>(input.clone()) {
46 serialize::structs::process(&input, cratename)
47 } else if let Ok(input) = syn::parse::<ItemEnum>(input.clone()) {
48 serialize::enums::process(&input, cratename)
49 } else if let Ok(input) = syn::parse::<ItemUnion>(input) {
50 serialize::unions::process(&input, cratename)
51 } else {
52 unreachable!()
54 };
55 TokenStream::from(match res {
56 Ok(res) => res,
57 Err(err) => err.to_compile_error(),
58 })
59}
60
61#[proc_macro_derive(BorshDeserialize, attributes(borsh))]
65pub fn borsh_deserialize(input: TokenStream) -> TokenStream {
66 let cratename = match check_attrs_get_cratename(&input) {
67 Ok(cratename) => cratename,
68 Err(err) => {
69 return err.to_compile_error().into();
70 }
71 };
72
73 let res = if let Ok(input) = syn::parse::<ItemStruct>(input.clone()) {
74 deserialize::structs::process(&input, cratename)
75 } else if let Ok(input) = syn::parse::<ItemEnum>(input.clone()) {
76 deserialize::enums::process(&input, cratename)
77 } else if let Ok(input) = syn::parse::<ItemUnion>(input) {
78 deserialize::unions::process(&input, cratename)
79 } else {
80 unreachable!()
82 };
83 TokenStream::from(match res {
84 Ok(res) => res,
85 Err(err) => err.to_compile_error(),
86 })
87}
88
89#[cfg(feature = "schema")]
93#[proc_macro_derive(BorshSchema, attributes(borsh))]
94pub fn borsh_schema(input: TokenStream) -> TokenStream {
95 let cratename = match check_attrs_get_cratename(&input) {
96 Ok(cratename) => cratename,
97 Err(err) => {
98 return err.to_compile_error().into();
99 }
100 };
101
102 let res = if let Ok(input) = syn::parse::<ItemStruct>(input.clone()) {
103 schema::structs::process(&input, cratename)
104 } else if let Ok(input) = syn::parse::<ItemEnum>(input.clone()) {
105 schema::enums::process(&input, cratename)
106 } else if syn::parse::<ItemUnion>(input).is_ok() {
107 Err(syn::Error::new(
108 Span::call_site(),
109 "Borsh schema does not support unions yet.",
110 ))
111 } else {
112 unreachable!()
114 };
115 TokenStream::from(match res {
116 Ok(res) => res,
117 Err(err) => err.to_compile_error(),
118 })
119}