codedefender 0.1.6

A macro used to mark a function for obfuscation by CodeDefender
Documentation
extern crate proc_macro;
use proc_macro::TokenStream;
use quote::{format_ident, quote};
use syn::{Expr, ItemFn, parse_macro_input};

#[proc_macro_attribute]
pub fn codedefender(attr: TokenStream, item: TokenStream) -> TokenStream {
    let input_fn = parse_macro_input!(item as ItemFn);
    let profile_expr = parse_macro_input!(attr as Expr);
    let profile_str = match profile_expr {
        syn::Expr::Lit(syn::ExprLit {
            lit: syn::Lit::Str(lit),
            ..
        }) => lit.value(),
        _ => panic!("Expected a string literal, e.g. #[codedefender(\"Profile1\")]"),
    };

    let fn_name = &input_fn.sig.ident;
    let upper_name = fn_name.to_string().to_uppercase();
    let struct_name = format_ident!("CDMacroEntry_{}", upper_name);
    let static_ident = format_ident!("CDMACRO_STATIC_{}", upper_name);
    let mut profile_bytes = profile_str.into_bytes();
    profile_bytes.push(0);
    let profile_len = profile_bytes.len();
    let byte_tokens = profile_bytes.iter().map(|b| quote! { #b });

    let expanded = quote! {
        #[inline(never)]
        #input_fn

        #[repr(C, packed)]
        struct #struct_name {
            p_func: *const (),
            p_profile: [u8; #profile_len],
        }

        unsafe impl Sync for #struct_name {}

        #[used]
        #[unsafe(link_section = ".cdmacro")]
        static #static_ident: #struct_name = #struct_name {
            p_func: #fn_name as *const (),
            p_profile: [#(#byte_tokens),*],
        };
    };

    expanded.into()
}