1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115
use proc_macro::TokenStream; use proc_macro2::{Ident as Ident2, TokenStream as TokenStream2}; use quote::{quote, TokenStreamExt}; use syn::{parse_macro_input, Data, DataStruct, DeriveInput, Fields}; #[proc_macro_derive(CLTyped)] pub fn derive_cl_typed(input: TokenStream) -> TokenStream { let input = parse_macro_input!(input as DeriveInput); let ident = input.ident; let expanded = quote! { impl casper_types::CLTyped for #ident { fn cl_type() -> casper_types::CLType { casper_types::CLType::Any } } }; TokenStream::from(expanded) } fn named_fields(input: DeriveInput) -> Result<Vec<Ident2>, TokenStream> { let fields = match input.data { Data::Struct(DataStruct { fields: Fields::Named(named_fields), .. }) => named_fields .named .into_iter() .map(|x| x.ident.unwrap()) .collect::<Vec<_>>(), _ => { return Err(TokenStream::from( quote! { compile_error!("Expected a struct with named fields."); }, )) } }; Ok(fields) } #[proc_macro_derive(FromBytes)] pub fn derive_from_bytes(input: TokenStream) -> TokenStream { let input = parse_macro_input!(input as DeriveInput); let struct_ident = input.ident.clone(); let fields = match named_fields(input) { Ok(fields) => fields, Err(error_stream) => return error_stream, }; let mut deserialize_fields = TokenStream2::new(); deserialize_fields.append_all(fields.iter().map(|ident| { quote! { let (#ident, bytes) = casper_types::bytesrepr::FromBytes::from_bytes(bytes)?; } })); let mut construct_struct = TokenStream2::new(); construct_struct.append_all(fields.iter().map(|ident| quote! { #ident, })); let expanded = quote! { impl casper_types::bytesrepr::FromBytes for #struct_ident { fn from_bytes(bytes: &[u8]) -> Result<(Self, &[u8]), casper_types::bytesrepr::Error> { #deserialize_fields let value = #struct_ident { #construct_struct }; Ok((value, bytes)) } } }; TokenStream::from(expanded) } #[proc_macro_derive(ToBytes)] pub fn derive_to_bytes(input: TokenStream) -> TokenStream { let input = parse_macro_input!(input as DeriveInput); let struct_ident = input.ident.clone(); let fields = match named_fields(input) { Ok(fields) => fields, Err(error_stream) => return error_stream, }; let mut sum_serialized_lengths = TokenStream2::new(); sum_serialized_lengths.append_all(fields.iter().map(|ident| { quote! { size += self.#ident.serialized_length(); } })); let mut append_bytes = TokenStream2::new(); append_bytes.append_all(fields.iter().map(|ident| { quote! { vec.extend(self.#ident.to_bytes()?); } })); let expanded = quote! { impl casper_types::bytesrepr::ToBytes for #struct_ident { fn serialized_length(&self) -> usize { let mut size = 0; #sum_serialized_lengths return size; } fn to_bytes(&self) -> Result<Vec<u8>, casper_types::bytesrepr::Error> { let mut vec = Vec::with_capacity(self.serialized_length()); #append_bytes Ok(vec) } } }; TokenStream::from(expanded) }