into_inner_derive 0.1.2

Derive macro for IntoInner trait
Documentation
#![deny(rustdoc::broken_intra_doc_links)]

//! # `into_inner_derive`
//!
//! This crate provides the procedural macro for automatically implementing the [`IntoInner`] trait
//! for tuple structs with a single field.
//!
//! ## Usage
//!
//! Normally, you do **not** use this crate directly. Instead, use the macro re-exported by the main crate `into_inner`:
//!
//! ```rust,ignore
//! use into_inner::IntoInner; // import both the trait and the derive macro
//!
//! #[derive(IntoInner)]
//! struct MyWrapper(String);
//! ```
//!
//! ## Limitations
//!
//! - The macro only works for tuple structs with a single field.
//! - It will generate a compile-time error if used on unsupported struct types.
//!
//! ## Note
//!
//! The macro expects the [`IntoInner`] trait to be in scope (imported).

use proc_macro::TokenStream;
use quote::quote;
use syn::{Data, DeriveInput, Error, Fields, parse_macro_input};

/// A derive macro for automatically implementing the `IntoInner` trait for tuple structs.
///
/// The `#[derive(IntoInner)]` macro generates an implementation of the `into_inner::IntoInner` trait  for
/// tuple structs with a single field. This allows you to easily extract the inner value from
/// the wrapper without manually implementing the trait.
///
/// # Usage
///
/// Normally, you do **not** use this crate directly. Instead, use the macro re-exported by the main crate `into_inner`:
///
/// ```rust,ignore
/// use into_inner::IntoInner; // import both the trait and the derive macro
///
/// #[derive(IntoInner)]
/// struct MyWrapper(String);
/// ```
///
/// # Requirements
///
/// - The macro can only be applied to **tuple structs** with exactly one field.
/// - Applying the macro to a struct with named fields or multiple fields will result in a
///   compile-time error.
///
/// # Generated Code
///
/// For a tuple struct like:
///
/// ```ignore
/// struct MyWrapper(String);
/// ```
///
/// The macro generates the following implementation:
///
/// ```ignore
/// impl IntoInner for MyWrapper {
///     type InnerType = String;
///
///     fn into_inner(self) -> Self::InnerType {
///         self.0
///     }
/// }
/// ```
///
/// # Examples
///
/// ## Basic Usage
///
/// ```ignore
/// use into_inner::IntoInner;
///
/// #[derive(IntoInner)]
/// struct MyWrapper(String);
///
/// let wrapper = MyWrapper("Hello, world!".to_string());
/// let inner = wrapper.into_inner();
/// assert_eq!(inner, "Hello, world!");
/// ```
///
/// ## Compile-Time Errors
///
/// The macro will generate a compile-time error if applied to a struct with multiple fields:
///
/// ```rust,compile_fail
/// use into_inner::IntoInner;
///
/// #[derive(IntoInner)]
/// struct InvalidWrapper(String, i32); // Error: `#[derive(IntoInner)]` supports only tuple structs with one field
/// ```
///
/// Or if applied to a struct with named fields:
///
/// ```rust,compile_fail
/// use into_inner::IntoInner;
///
/// #[derive(IntoInner)]
/// struct NamedFieldsWrapper {
///     field: String,
/// } // Error: `#[derive(IntoInner)]` can only be used on tuple structs
/// ```
///
/// ## Generic Tuple Structs
///
/// The macro also works with generic tuple structs:
///
/// ```ignore
/// use into_inner::IntoInner;
///
/// #[derive(IntoInner)]
/// struct GenericWrapper<T>(T);
///
/// let wrapper = GenericWrapper(42);
/// let inner = wrapper.into_inner();
/// assert_eq!(inner, 42);
/// ```
#[proc_macro_derive(IntoInner)]
pub fn derive_into_inner(input: TokenStream) -> TokenStream {
    let input = parse_macro_input!(input as DeriveInput);
    let name = &input.ident;
    let generics = &input.generics;
    let (impl_generics, ty_generics, where_clause) = generics.split_for_impl();

    // Verify that the struct is a tuple struct with a single field
    let inner_type = match input.data {
        Data::Struct(ref s) => match &s.fields {
            Fields::Unnamed(fields) if fields.unnamed.len() == 1 => {
                &fields.unnamed.first().unwrap().ty
            }
            _ => {
                return Error::new_spanned(
                    &s.fields,
                    "`#[derive(IntoInner)]` supports only tuple structs with one field",
                )
                .to_compile_error()
                .into();
            }
        },
        _ => {
            return Error::new_spanned(
                &input,
                "`#[derive(IntoInner)]` can only be used on tuple structs",
            )
            .to_compile_error()
            .into();
        }
    };

    // Generate the code for the `into_inner` method and the implementation of the `IntoInner` trait
    let expanded = quote! {
        impl #impl_generics #name #ty_generics #where_clause {
            /// Consumes the struct and returns the inner value.
            pub fn into_inner(self) -> #inner_type {
                self.0
            }
        }

        impl #impl_generics IntoInner for #name #ty_generics #where_clause {
            type InnerType = #inner_type;

            /// Consumes the struct and returns the inner value.
            fn into_inner(self) -> Self::InnerType {
                self.0
            }
        }
    };

    TokenStream::from(expanded)
}