Add ssz_derive crate.
				
					
				
			It appears to be fully functional at this stage.
This commit is contained in:
		
							parent
							
								
									98c33a7d06
								
							
						
					
					
						commit
						fdfaf18dbd
					
				| @ -12,6 +12,7 @@ members = [ | |||||||
| 	"eth2/utils/int_to_bytes", | 	"eth2/utils/int_to_bytes", | ||||||
| 	"eth2/utils/slot_clock", | 	"eth2/utils/slot_clock", | ||||||
| 	"eth2/utils/ssz", | 	"eth2/utils/ssz", | ||||||
|  | 	"eth2/utils/ssz_derive", | ||||||
| 	"eth2/utils/swap_or_not_shuffle", | 	"eth2/utils/swap_or_not_shuffle", | ||||||
| 	"eth2/utils/fisher_yates_shuffle", | 	"eth2/utils/fisher_yates_shuffle", | ||||||
| 	"beacon_node", | 	"beacon_node", | ||||||
|  | |||||||
| @ -18,6 +18,7 @@ serde_derive = "1.0" | |||||||
| serde_json = "1.0" | serde_json = "1.0" | ||||||
| slog = "^2.2.3" | slog = "^2.2.3" | ||||||
| ssz = { path = "../utils/ssz" } | ssz = { path = "../utils/ssz" } | ||||||
|  | ssz_derive = { path = "../utils/ssz_derive" } | ||||||
| swap_or_not_shuffle = { path = "../utils/swap_or_not_shuffle" } | swap_or_not_shuffle = { path = "../utils/swap_or_not_shuffle" } | ||||||
| 
 | 
 | ||||||
| [dev-dependencies] | [dev-dependencies] | ||||||
|  | |||||||
							
								
								
									
										14
									
								
								eth2/utils/ssz_derive/Cargo.toml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										14
									
								
								eth2/utils/ssz_derive/Cargo.toml
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,14 @@ | |||||||
|  | [package] | ||||||
|  | name = "ssz_derive" | ||||||
|  | version = "0.1.0" | ||||||
|  | authors = ["Paul Hauner <paul@paulhauner.com>"] | ||||||
|  | edition = "2018" | ||||||
|  | description = "Procedural derive macros for SSZ encoding and decoding." | ||||||
|  | 
 | ||||||
|  | [lib] | ||||||
|  | proc-macro = true | ||||||
|  | 
 | ||||||
|  | [dependencies] | ||||||
|  | syn = "0.15" | ||||||
|  | quote = "0.6" | ||||||
|  | ssz = { path = "../ssz" } | ||||||
							
								
								
									
										80
									
								
								eth2/utils/ssz_derive/src/lib.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										80
									
								
								eth2/utils/ssz_derive/src/lib.rs
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,80 @@ | |||||||
|  | extern crate proc_macro; | ||||||
|  | 
 | ||||||
|  | use proc_macro::TokenStream; | ||||||
|  | use quote::quote; | ||||||
|  | use syn::{parse_macro_input, DeriveInput}; | ||||||
|  | 
 | ||||||
|  | fn get_named_field_idents<'a>(struct_data: &'a syn::DataStruct) -> Vec<&'a syn::Ident> { | ||||||
|  |     struct_data.fields.iter().map(|f| { | ||||||
|  |         match &f.ident { | ||||||
|  |             Some(ref ident) => ident, | ||||||
|  |             _ => panic!("ssz_derive only supports named struct fields.") | ||||||
|  |         } | ||||||
|  |     }).collect() | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | #[proc_macro_derive(Encode)] | ||||||
|  | pub fn ssz_encode_derive(input: TokenStream) -> TokenStream { | ||||||
|  |     let item = parse_macro_input!(input as DeriveInput); | ||||||
|  | 
 | ||||||
|  |     let name = &item.ident; | ||||||
|  | 
 | ||||||
|  |     let struct_data = match &item.data { | ||||||
|  |         syn::Data::Struct(s) => s, | ||||||
|  |         _ => panic!("ssz_derive only supports structs.") | ||||||
|  |     }; | ||||||
|  | 
 | ||||||
|  |     let field_idents = get_named_field_idents(&struct_data); | ||||||
|  | 
 | ||||||
|  |     let output = quote! { | ||||||
|  |         impl Encodable for #name { | ||||||
|  |             fn ssz_append(&self, s: &mut SszStream) { | ||||||
|  |                 #( | ||||||
|  |                     s.append(&self.#field_idents); | ||||||
|  |                 )* | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     }; | ||||||
|  |     output.into() | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | #[proc_macro_derive(Decode)] | ||||||
|  | pub fn ssz_decode_derive(input: TokenStream) -> TokenStream { | ||||||
|  |     let item = parse_macro_input!(input as DeriveInput); | ||||||
|  | 
 | ||||||
|  |     let name = &item.ident; | ||||||
|  | 
 | ||||||
|  |     let struct_data = match &item.data { | ||||||
|  |         syn::Data::Struct(s) => s, | ||||||
|  |         _ => panic!("ssz_derive only supports structs.") | ||||||
|  |     }; | ||||||
|  | 
 | ||||||
|  |     let field_idents = get_named_field_idents(&struct_data); | ||||||
|  | 
 | ||||||
|  |     // Using a var in an iteration always consumes the var, therefore we must make a `fields_a` and
 | ||||||
|  |     // a `fields_b` in order to perform two loops.
 | ||||||
|  |     //
 | ||||||
|  |     // https://github.com/dtolnay/quote/issues/8
 | ||||||
|  |     let field_idents_a = &field_idents; | ||||||
|  |     let field_idents_b = &field_idents; | ||||||
|  | 
 | ||||||
|  |     let output = quote! { | ||||||
|  |         impl Decodable for #name { | ||||||
|  |             fn ssz_decode(bytes: &[u8], i: usize) -> Result<(Self, usize), DecodeError> { | ||||||
|  |                 #( | ||||||
|  |                     let (#field_idents_a, i) = <_>::ssz_decode(bytes, i)?; | ||||||
|  |                 )* | ||||||
|  | 
 | ||||||
|  |                 Ok(( | ||||||
|  |                     Self { | ||||||
|  |                         #( | ||||||
|  |                             #field_idents_b, | ||||||
|  |                         )* | ||||||
|  |                     }, | ||||||
|  |                     i | ||||||
|  |                 )) | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     }; | ||||||
|  |     output.into() | ||||||
|  | } | ||||||
		Loading…
	
		Reference in New Issue
	
	Block a user