[workspace]
resolver = "3"
cargo init serialize_macro_traits --lib
use std::fmt::Error;

pub trait Serialize {
	fn serialize(&self) -> Vec<u8>;
}

pub trait Deserialize: Sized {
	fn deserialize(base: &[u8]) -> Result<Self, Error>;
}
cargo init serialize_macro --lib
[lib]
proc-macro = true
[dependencies]
syn = "2.0"
quote = "1.0"
use proc_macro::TokenStream;
use quote::quote;

#[proc_macro_derive(SerializeNumberStruct)]
pub fn serialise_number_struct(input: TokenStream) -> TokenStream {
    // Construct a representation of Rust code as a syntax tree
    // that we can manipulate.
    let ast = syn::parse(input).unwrap();

    // Build the trait implementation.
    
}

#[proc_macro_derive(DeserializeNumberStruct)]
pub fn deserialise_number_struct(input: TokenStream) -> TokenStream {
    // Construct a representation of Rust code as a syntax tree
    // that we can manipulate.
    let ast = syn::parse(input).unwrap();

    
}

use proc_macro::TokenStream;
use quote::quote;
use syn::{DeriveInput, Data, Fields};

#[proc_macro_derive(SerializeNumberStruct)]
pub fn serialise_number_struct(input: TokenStream) -> TokenStream {
    let ast: DeriveInput = syn::parse(input).unwrap();
    let name = &ast.ident;

    let serialize_fields = match &ast.data {
        Data::Struct(data_struct) => {
            match &data_struct.fields {
                Fields::Named(fields) => {
                    let field_serializations = fields.named.iter().map(|field| {
                        let field_name = &field.ident;
                        quote! {
                            result.extend_from_slice(&self.#field_name.to_be_bytes());
                        }
                    });
                    /*
                        field_serializeations = [quote!(result.extend_from_slice(&self.qty_1.to_be_bytes())), quote!(result.extend_from_slice(&self.qty_2.to_be_bytes()))]
                     */
                    quote! {
                        #(#field_serializations)*
                    }
                }
                _ => panic!("Only named fields are supported"),
            }
        }
        _ => panic!("Only structs are supported"),
    };
    /*
        serialize_fields ->
        result.extend_from_slice(&self.qty_1.to_be_bytes())
        result.extend_from_slice(&self.qty_2.to_be_bytes())
        result.extend_from_slice(&self.qty_3.to_be_bytes())
     */

    let generated = quote! {
        impl Serialize for #name {
            fn serialize(&self) -> Vec<u8> {
                let mut result = Vec::new();
                #serialize_fields
                result
            }
        }
    };
    generated.into()
}

#[proc_macro_derive(DeserializeNumberStruct)]
pub fn deserialise_number_struct(input: TokenStream) -> TokenStream {
    let ast: DeriveInput = syn::parse(input).unwrap();
    let name = &ast.ident;

    let (deserialize_fields, field_assignments, total_size) = match &ast.data {
        Data::Struct(data_struct) => {
            match &data_struct.fields {
                Fields::Named(fields) => {
                    let mut offset: usize = 0;
                    let mut field_deserializations = Vec::new();
                    let mut field_assignments = Vec::new();
                    
                    for field in &fields.named {
                        let field_name = &field.ident;
                        let field_size = 4;
                        let start_offset = offset;
                        let end_offset = offset + field_size;
                        
                        field_deserializations.push(quote! {
                            let #field_name = {
                                let bytes: [u8; 4] = base[#start_offset..#end_offset]
                                    .try_into()
                                    .map_err(|_| Error)?;
                                i32::from_be_bytes(bytes)
                            };
                        });
                        
                        field_assignments.push(quote! {
                            #field_name
                        });
                        
                        offset += field_size;
                    }
                    
                    (field_deserializations, field_assignments, offset)
                }
                _ => panic!("Only named fields are supported"),
            }
        }
        _ => panic!("Only structs are supported"),
    };

    let generated = quote! {
        impl Deserialize for #name {
            fn deserialize(base: &[u8]) -> Result<Self, Error> {
                if base.len() < #total_size {
                    return Err(Error);
                }
                
                #(#deserialize_fields)*
                
                Ok(#name {
                    #(#field_assignments,)*
                })
            }
        }
    };
    generated.into()
}
cargo init --bin app
use std::fmt::Error;
use serialize_macro::{SerializeNumberStruct, DeserializeNumberStruct};
use serialize_macro_traits::{Serialize, Deserialize};

#[derive(SerializeNumberStruct, DeserializeNumberStruct)]
struct Swap {
    qty_1: i32,
    qty_2: i32,
    qty_3: i32
}

fn main() {
    println!("Hello, world!");
    let s = Swap {
        qty_1: 1,
        qty_2: 2,
        qty_3: 1000
    };
    let bytes = s.serialize();
    println!("{:?}", bytes);
}