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/slot_clock", | ||||
| 	"eth2/utils/ssz", | ||||
| 	"eth2/utils/ssz_derive", | ||||
| 	"eth2/utils/swap_or_not_shuffle", | ||||
| 	"eth2/utils/fisher_yates_shuffle", | ||||
| 	"beacon_node", | ||||
|  | ||||
| @ -18,6 +18,7 @@ serde_derive = "1.0" | ||||
| serde_json = "1.0" | ||||
| slog = "^2.2.3" | ||||
| ssz = { path = "../utils/ssz" } | ||||
| ssz_derive = { path = "../utils/ssz_derive" } | ||||
| swap_or_not_shuffle = { path = "../utils/swap_or_not_shuffle" } | ||||
| 
 | ||||
| [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