oors-macros 0.8.0

Macros for oors
Documentation
/*
 * Copyright (c) 2025 eligamii.
 * Licenced under the MIT licence. See the LICENCE file in the project for full licence information 
 */

use quote::{format_ident, quote, ToTokens};
use syn::{parse_macro_input, FnArg, ImplItem, ItemImpl, Visibility};

pub fn impl_object_impl(attr: proc_macro::TokenStream, struct_impl: proc_macro::TokenStream) -> proc_macro::TokenStream {
    
    let vis = if attr.is_empty() {
        Visibility::Inherited
    } else {
        parse_macro_input!(attr as Visibility)
    };
    
    let struct_impl = parse_macro_input!(struct_impl as ItemImpl);
    if struct_impl.trait_.is_some() {
        return quote!(compile_error!("Expected struct impl, found trait impl")).into();
    }

    let items = struct_impl.items.clone().into_iter();
    
    // items implemented for impl Struct { ... }
    let (non_self_items, self_items): (Vec<ImplItem>, Vec<ImplItem>) = items.partition(|item| match item {
        ImplItem::Const(_) |  ImplItem::Macro(_) | ImplItem::Type(_) => true,
        ImplItem::Fn(func) => {
            func.sig.inputs.iter().any(|p| match p { 
                FnArg::Receiver(_) => true,
                _ => false,
            })
        },
        _ => false
    });
    

    
    let struct_ty = struct_impl.self_ty.clone();
    let struct_impl_name = &struct_ty.to_token_stream().to_string()
        .chars().filter(|c| c.is_alphanumeric())
        .collect::<String>();

    let struct_impl_name = format_ident!("__{}Impl", struct_impl_name);

    let res = quote! {
        #[doc(hidden)]
        #vis trait #struct_impl_name where Self: oors::IsA<#struct_ty>, Self: Sized {
            #(#non_self_items)*
        }

        impl<T> #struct_impl_name for T where T: oors::IsA<#struct_ty> {}
        
        impl #struct_ty {
            #(#self_items)*
        }
    };

    
    res.into()
}