diff --git a/poppable-derive/src/lib.rs b/poppable-derive/src/lib.rs index e9e9307..18fd8a6 100644 --- a/poppable-derive/src/lib.rs +++ b/poppable-derive/src/lib.rs @@ -1,8 +1,49 @@ -use proc_macro::TokenStream; -use syn::DeriveInput; +use core::panic; -#[proc_macro_derive(PushPop)] +use proc_macro::TokenStream; +use quote::{quote, quote_spanned}; +use syn::{spanned::Spanned, DeriveInput}; + +#[proc_macro_derive(PushPopParse)] pub fn pushpop_derive_macro(item: TokenStream) -> TokenStream { - let _ast: DeriveInput = syn::parse(item).unwrap(); - todo!() + let ast: DeriveInput = syn::parse(item).unwrap(); + let struct_ident = ast.ident; + let struct_data: syn::DataStruct = match ast.data { + syn::Data::Struct(struct_data) => struct_data, + syn::Data::Enum(_) => panic!("Error: Enum support not implemented"), + syn::Data::Union(_) => panic!("Error: Union support not implemented"), + }; + + let recursive = struct_data.fields.iter().map(|f| { + let name = &f.ident; + let ty = &f.ty; + quote_spanned!(f.span()=> let #name = #ty::pop_ne_from(&mut source)?;) + }); + + let names = struct_data.fields.iter().map(|f| { + let name = &f.ident; + quote_spanned!(f.span()=> #name) + }); + let pop = struct_data.fields.iter().map(|f| { + let name = &f.ident; + quote_spanned!(f.span()=> PopFromNE::push_ne_into(&self.#name, dest)?;) + }); + + quote!( + impl PopFromNE for #struct_ident { + fn pop_ne_from(mut source: &mut &[u8]) -> Result + where + Self: Sized, + { + #(#recursive)* + Ok(#struct_ident{ + #(#names),* + }) + } + fn push_ne_into(&self, dest: &mut T) -> Result<()> { + #(#pop)* + Ok(()) + } + }) + .into() } diff --git a/src/lib.rs b/src/lib.rs index 1180b33..098cf16 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,6 +1,5 @@ -use std::u16; - use anyhow::{Ok, Result}; +pub use poppable_derive::PushPopParse; //pub type BytesRef = AsRef; @@ -236,3 +235,28 @@ flt_impl_pop_non_ne!(f32); core_impl_pop_ne!(f64); flt_impl_pop_non_ne!(f64); + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn it_works() { + let mut s: &[u8] = &vec![4, 8, 15, 16, 23, 42]; + let ans = u8::pop_ne_from(&mut s).unwrap(); + assert_eq!(ans, 4); + } + + #[test] + fn derive_test() { + #[derive(PushPopParse)] + struct Thing { + a: u8, + b: u8, + } + let mut s: &[u8] = &vec![4, 8, 15, 16, 23, 42]; + let thing = Thing::pop_ne_from(&mut s).unwrap(); + assert_eq!(thing.a, 4); + assert_eq!(thing.b, 8); + } +}