An unofficial collection of APIs used in FreeJam games and mods
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

50 lines
1.6KB

  1. //! Macro implementation for using #[derive(Parsable)]
  2. extern crate proc_macro;
  3. use proc_macro::{TokenStream};
  4. use syn::{DeriveInput, Data};
  5. use quote::quote;
  6. /// Macro generator
  7. #[proc_macro_derive(Parsable)]
  8. pub fn derive_parsable(struc: TokenStream) -> TokenStream {
  9. let ast: &DeriveInput = &syn::parse(struc).unwrap();
  10. let name = &ast.ident;
  11. if let Data::Struct(data_struct) = &ast.data {
  12. let mut p_fields_gen = vec![];
  13. let mut d_fields_gen = vec![];
  14. for field in &data_struct.fields {
  15. let field_ident = &field.ident.clone().expect("Expected named field");
  16. let field_type = &field.ty;
  17. p_fields_gen.push(
  18. quote! {
  19. #field_ident: <#field_type>::parse(data)?
  20. }
  21. );
  22. d_fields_gen.push(
  23. quote! {
  24. self.#field_ident.dump(data)?;
  25. }
  26. );
  27. }
  28. let final_gen = quote! {
  29. impl Parsable for #name {
  30. fn parse(data: &mut dyn std::io::Read) -> std::io::Result<Self> {
  31. Ok(Self{
  32. #(#p_fields_gen),*
  33. })
  34. }
  35. fn dump(&self, data: &mut dyn std::io::Write) -> std::io::Result<usize> {
  36. let mut write_count: usize = 0;
  37. #(write_count += #d_fields_gen;)*
  38. Ok(write_count)
  39. }
  40. }
  41. };
  42. return final_gen.into();
  43. } else {
  44. panic!("Expected Parsable auto-trait to be applied to struct");
  45. }
  46. }