#![allow(dead_code)]
use proc_macro2::{Span, TokenStream};
use quote::ToTokens;
use quote::{format_ident, quote};
use syn::{parse_macro_input, DeriveInput, Error, Result};
mod helpers;
use helpers::{Abi, BytesOf, Generate, Zeroable};
const ABIO_DEBUG: &str = "ABIO_DEBUG";
#[proc_macro_derive(Abi)]
pub fn derive_abi(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
derive_marker_trait_inner::<Abi>(input)
}
#[proc_macro_derive(BytesOf)]
pub fn derive_as_bytes(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
derive_marker_trait_inner::<BytesOf>(input)
}
#[proc_macro_derive(Zeroable)]
pub fn derive_zeroable(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
derive_marker_trait_inner::<Zeroable>(input)
}
fn derive_marker_trait_inner<G: Generate>(
input: proc_macro::TokenStream,
) -> proc_macro::TokenStream {
let input = parse_macro_input!(input as DeriveInput);
generate_trait_impl::<G>(input).unwrap_or_else(|e| e.into_compile_error()).into()
}
#[proc_macro_derive(Decode)]
pub fn derive_decode(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
let input = parse_macro_input!(input as DeriveInput);
let expanded = parse_decode_input(&input);
TokenStream::from(expanded).into()
}
fn inspect_input(tts: proc_macro::TokenStream) -> proc_macro::TokenStream {
let parsed = parse_macro_input!(tts as DeriveInput);
println!("{parsed:#?}");
proc_macro::TokenStream::from(parsed.to_token_stream())
}
fn parse_decode_input(input: &DeriveInput) -> proc_macro2::TokenStream {
let name = format_ident!("{}", input.ident);
quote! {
#name
}
}
fn derive_decode_trait(_input: &DeriveInput) -> TokenStream {
unimplemented!()
}
fn generate_trait_impl<G: Generate>(mut input: DeriveInput) -> Result<proc_macro2::TokenStream> {
let trait_name = G::ident(&input);
G::add_trait_marker(&mut input.generics, &trait_name);
let name = &input.ident;
let (impl_generics, ty_generics, where_clause) = input.generics.split_for_impl();
G::check_attributes(&input.data, &input.attrs).map_err(|err| {
eprintln!("{err:?}");
Error::new(
Span::call_site(),
"Cannot implement this trait for this type due to invalid attribute values.",
)
})?;
let assertions = match G::asserts(&input) {
Ok(asserts) => asserts,
Err(err) => err.into_compile_error().to_token_stream(),
};
let (trait_impl_extras, trait_impl) = G::trait_impl(&input)?;
let impl_prefix = if G::is_unsafe(&input) {
quote! {
unsafe impl
}
} else {
quote! {
impl
}
};
let implies_trait = if let Some(implies_trait) = G::fulfills_contract() {
quote! {
#impl_prefix #impl_generics #implies_trait for #name #ty_generics #where_clause {}
}
} else {
quote! {}
};
let where_clause = if G::requires_where_clause() { where_clause } else { None };
Ok(quote! {
#assertions
#trait_impl_extras
#impl_prefix #impl_generics #trait_name for #name #ty_generics #where_clause {
#trait_impl
}
#implies_trait
})
}