chorba_macro 0.1.0

chorba macro
Documentation
use std::str::FromStr;

use proc_macro::TokenStream;
use quote::ToTokens;

#[proc_macro_derive(Encode)]
pub fn derive_encode(item: TokenStream) -> TokenStream {
    let mut new_code = "".to_string();

    let ast = syn::parse_macro_input!(item as syn::ItemStruct);

    let struct_name = ast.ident.to_string();

    new_code += format!(r#"impl chorba::Encoder for {struct_name} {{"#).as_str();

    {
        new_code += r#"fn encode(&self) -> Vec<u8> {"#;

        {
            new_code += r#"let mut buffer = Vec::new();"#;

            for field in ast.fields.iter() {
                let field_name = field.ident.as_ref().unwrap().to_string();

                new_code +=
                    format!(r#"let bytes = chorba::Encoder::encode(&self.{field_name});"#).as_str();
                new_code += format!(r#"buffer.extend(bytes);"#).as_str();
            }

            new_code += r#"buffer"#;
        }

        new_code += r#"}"#;
    }

    new_code += "}";

    return TokenStream::from_str(new_code.as_str()).unwrap();
}

#[proc_macro_derive(Decode)]
pub fn derive_decode(item: TokenStream) -> TokenStream {
    let mut new_code = "".to_string();

    let ast = syn::parse_macro_input!(item as syn::ItemStruct);

    let struct_name = ast.ident.to_string();

    new_code += format!(r#"impl chorba::Decoder<{struct_name}> for {struct_name} {{"#).as_str();

    {
        new_code +=
            format!(r#"fn decode(buffer: &[u8]) -> Result<{struct_name}, chorba::DecodeError> {{"#)
                .as_str();

        {
            let mut field_names = vec![];

            for field in ast.fields.iter() {
                let field_name = field.ident.as_ref().unwrap().to_string();
                let field_type = field.ty.to_token_stream().to_string();

                field_names.push(field_name.clone());

                new_code +=
                    format!(r#"let ({field_name}_bytes, buffer) = chorba::deserialize(buffer).ok_or(chorba::DecodeError::InvalidLength)?;"#)
                        .as_str();

                new_code +=
                    format!(r#"let {field_name} = <{field_type} as chorba::Decoder::<{field_type}>>::decode({field_name}_bytes)?;"#)
                        .as_str();
            }

            new_code += format!(r#"Ok({struct_name} {{"#).as_str();

            for field_name in field_names.iter() {
                new_code += format!(r#"{field_name},"#).as_str();
            }

            new_code += "})";
        }

        new_code += r#"}"#;
    }

    new_code += "}";

    return TokenStream::from_str(new_code.as_str()).unwrap();
}