infiltrait 0.1.0

A procedural macro that automatically generates trait definitions from implementation blocks
Documentation
//! # Infiltrait
//!
//! A procedural macro that automatically generates trait definitions from implementation blocks.
//!
//! The `#[infiltrait]` attribute macro allows you to define a trait and its implementation
//! simultaneously by writing only the impl block. This eliminates the need to separately
//! define the trait interface, reducing code duplication and keeping related code together.
//!
//! ## Usage
//!
//! ```rust
//! use infiltrait::infiltrait;
//!
//! struct MyStruct;
//!
//! #[infiltrait]
//! impl MyTrait for MyStruct {
//!     const MAGIC_NUMBER: i32 = 42;
//!     type Output = String;
//!
//!      fn hello(&self) -> Output {
//!         format!("Constant magic number: {}", MAGIC_NUMBER)
//!     }
//! }
//!
//! // Generated code:
//! // trait MyTrait {
//! //     type Output;
//! //     const MAGIC_NUMBER: i32;
//! //     fn hello(&self) -> String;
//! // }
//! //
//! // impl MyTrait for MyStruct {
//! //     const MAGIC_NUMBER: i32 = 42;
//! //     type Output = String;
//!
//! //     fn hello(&self) -> Output {
//! //        format!("Constant magic number: {}", MAGIC_NUMBER)
//! //    }
//! // }
//! ```
//!
//! ## Features
//!
//! - Automatically generates trait definitions from impl blocks
//! - Supports methods, associated constants, and associated types
//! - Preserves visibility modifiers and unsafe markers
//! - Provides clear compile-time error messages
//! - Zero runtime overhead
//!
//! ## Limitations
//!
//! - Trait names cannot contain lifetimes or generic parameters
//! - Only supports trait implementations (not inherent impls)
//!
//! ## Examples
//!
//! ### Basic Usage
//!
//! ```rust
//! # use infiltrait::infiltrait;
//! struct Calculator;
//!
//! #[infiltrait]
//! impl Arithmetic for Calculator {
//!     fn add(&self, a: i32, b: i32) -> i32 {
//!         a + b
//!     }
//!
//!     fn multiply(&self, a: i32, b: i32) -> i32 {
//!         a * b
//!     }
//! }
//! ```
//!
//! ### With Associated Types and Constants
//!
//! ```rust
//! # use infiltrait::infiltrait;
//! struct Database;
//!
//! #[infiltrait]
//! impl Storage for Database {
//!     type Item = String;
//!     const MAX_ITEMS: usize = 1000;
//!
//!     fn store(&mut self, item: Self::Item) -> Result<(), &'static str> {
//!         Ok(()) // Implementation details...
//!     }
//! }
//! ```
//!
//! ### Public Traits
//!
//! ```rust
//! # use infiltrait::infiltrait;
//! struct Service;
//!
//! #[infiltrait]
//! pub impl PublicApi for Service {
//!     fn process(&self, data: &str) -> String {
//!         data.to_uppercase()
//!     }
//! }
//! ```

extern crate proc_macro;
use proc_macro::TokenStream;

/// The main procedural macro that generates trait definitions from implementation blocks.
///
/// This attribute macro takes an `impl TraitName for Type` block and automatically
/// generates the corresponding trait definition, then outputs both the trait and
/// the implementation.
///
/// # Arguments
///
/// * `_attr` - Attribute arguments (currently unused)
/// * `item` - The implementation block to process
///
/// # Returns
///
/// A `TokenStream` containing both the generated trait definition and the original
/// implementation block.
///
/// # Errors
///
/// This macro will produce compile-time errors if:
/// - The input is not a trait implementation (missing trait name)
/// - The trait name contains lifetimes or generic parameters
/// - The input cannot be parsed as a valid implementation block
///
/// # Examples
///
/// ```rust
/// # use infiltrait::infiltrait;
/// struct MyStruct;
///
/// #[infiltrait]
/// impl MyTrait for MyStruct {
///     fn greet(&self) -> &'static str {
///         "Hello!"
///     }
/// }
///
/// // Now you can use MyTrait as a regular trait:
/// fn use_trait<T: MyTrait>(obj: &T) {
///     println!("{}", obj.greet());
/// }
/// ```
#[proc_macro_attribute]
pub fn infiltrait(_attr: TokenStream, item: TokenStream) -> TokenStream {
    let undefined_implementation = syn::parse_macro_input!(item as DefinableImplementation);

    let implementation = undefined_implementation.impl_block.clone();
    let definition = match create_trait_definition(undefined_implementation) {
        Ok(def) => def,
        Err(e) => return e.into_compile_error().into(),
    };

    quote::quote! {
       #definition

       #implementation
    }
    .into()
}

/// Creates a trait definition from an implementation block.
///
/// This function extracts the trait name from the impl block and converts all
/// impl items (methods, constants, types) into their corresponding trait items
/// by removing method bodies and implementation details.
///
/// # Errors
///
/// Returns an error if:
/// - No trait name is specified in the impl block
/// - The trait name contains lifetimes or generic parameters
fn create_trait_definition(
    DefinableImplementation {
        visibility: impl_visibility,
        impl_block,
    }: DefinableImplementation,
) -> syn::Result<syn::ItemTrait> {
    let trait_ident = match impl_block
        .trait_
        .clone()
        .map(|(_, path, _)| path.get_ident().cloned())
    {
        Some(Some(ident)) => ident,
        None => {
            return Err(syn::Error::new_spanned(
                impl_block,
                "Please name a trait to implement",
            ));
        }
        Some(None) => {
            return Err(syn::Error::new_spanned(
                impl_block,
                "Trait may not contain lifetimes or generics",
            ));
        }
    };

    Ok(syn::ItemTrait {
        vis: impl_visibility,
        unsafety: impl_block.unsafety,
        ident: trait_ident,
        items: impl_block
            .items
            .into_iter()
            .filter_map(create_trait_item)
            .collect(),
        attrs: Vec::new(),
        auto_token: None,
        restriction: None,
        trait_token: Default::default(),
        generics: impl_block.generics,
        colon_token: None,
        brace_token: Default::default(),
        supertraits: Default::default(),
    })
}

/// Converts an implementation item into its corresponding trait item.
///
/// This function transforms impl block items (which have implementations)
/// into trait items (which are just signatures). Method bodies are removed,
/// constant values become defaults set to `None`, and type implementations
/// become associated type declarations.
///
/// # Arguments
///
/// * `impl_item` - The implementation item to convert
///
/// # Returns
///
/// An `Option<syn::TraitItem>` containing the converted trait item, or `None`
/// if the impl item type is not supported (e.g., macros, verbatim items).
///
/// # Supported Item Types
///
/// - **Constants**: `const FOO: i32 = 42;` becomes `const FOO: i32;`
/// - **Functions**: Method implementations become method signatures
/// - **Types**: `type Foo = Bar;` becomes `type Foo;`
fn create_trait_item(impl_item: syn::ImplItem) -> Option<syn::TraitItem> {
    match impl_item {
        syn::ImplItem::Const(impl_item_const) => Some(syn::TraitItem::Const(syn::TraitItemConst {
            attrs: impl_item_const.attrs,
            const_token: impl_item_const.const_token,
            ident: impl_item_const.ident,
            generics: impl_item_const.generics,
            colon_token: impl_item_const.colon_token,
            ty: impl_item_const.ty,
            default: None,
            semi_token: impl_item_const.semi_token,
        })),
        syn::ImplItem::Fn(impl_item_fn) => Some(syn::TraitItem::Fn(syn::TraitItemFn {
            attrs: impl_item_fn.attrs,
            sig: impl_item_fn.sig,
            default: None,
            semi_token: Some(Default::default()),
        })),
        syn::ImplItem::Type(impl_item_type) => Some(syn::TraitItem::Type(syn::TraitItemType {
            attrs: impl_item_type.attrs,
            type_token: impl_item_type.type_token,
            ident: impl_item_type.ident,
            generics: impl_item_type.generics,
            colon_token: None,
            bounds: Default::default(),
            default: None,
            semi_token: Default::default(),
        })),
        _ => None,
    }
}

/// A parsed representation of an implementation block with its visibility modifier.
///
/// This struct combines the visibility modifier (pub, pub(crate), etc.) with
/// the implementation block itself. It's used as an intermediate representation
/// during parsing to ensure we capture both the visibility that should be applied
/// to the generated trait and the implementation details.
///
/// # Fields
///
/// * `visibility` - The visibility modifier applied to the impl block
/// * `impl_block` - The parsed implementation block
struct DefinableImplementation {
    visibility: syn::Visibility,
    impl_block: syn::ItemImpl,
}

/// Parser implementation for `DefinableImplementation`.
///
/// This implementation allows `DefinableImplementation` to be parsed directly
/// from a `TokenStream` by first parsing the visibility modifier, then the
/// implementation block.
impl syn::parse::Parse for DefinableImplementation {
    fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
        Ok(DefinableImplementation {
            visibility: input.parse()?,
            impl_block: input.parse()?,
        })
    }
}