into_inner_derive/
lib.rs

1#![deny(rustdoc::broken_intra_doc_links)]
2
3//! # `into_inner_derive`
4//!
5//! This crate provides the procedural macro for automatically implementing the [`IntoInner`] trait
6//! for tuple structs with a single field.
7//!
8//! ## Usage
9//!
10//! Normally, you do **not** use this crate directly. Instead, use the macro re-exported by the main crate `into_inner`:
11//!
12//! ```rust,ignore
13//! use into_inner::IntoInner; // import both the trait and the derive macro
14//!
15//! #[derive(IntoInner)]
16//! struct MyWrapper(String);
17//! ```
18//!
19//! ## Limitations
20//!
21//! - The macro only works for tuple structs with a single field.
22//! - It will generate a compile-time error if used on unsupported struct types.
23//!
24//! ## Note
25//!
26//! The macro expects the [`IntoInner`] trait to be in scope (imported).
27
28use proc_macro::TokenStream;
29use quote::quote;
30use syn::{Data, DeriveInput, Error, Fields, parse_macro_input};
31
32/// A derive macro for automatically implementing the `IntoInner` trait for tuple structs.
33///
34/// The `#[derive(IntoInner)]` macro generates an implementation of the `into_inner::IntoInner` trait  for
35/// tuple structs with a single field. This allows you to easily extract the inner value from
36/// the wrapper without manually implementing the trait.
37///
38/// # Usage
39///
40/// Normally, you do **not** use this crate directly. Instead, use the macro re-exported by the main crate `into_inner`:
41///
42/// ```rust,ignore
43/// use into_inner::IntoInner; // import both the trait and the derive macro
44///
45/// #[derive(IntoInner)]
46/// struct MyWrapper(String);
47/// ```
48///
49/// # Requirements
50///
51/// - The macro can only be applied to **tuple structs** with exactly one field.
52/// - Applying the macro to a struct with named fields or multiple fields will result in a
53///   compile-time error.
54///
55/// # Generated Code
56///
57/// For a tuple struct like:
58///
59/// ```ignore
60/// struct MyWrapper(String);
61/// ```
62///
63/// The macro generates the following implementation:
64///
65/// ```ignore
66/// impl IntoInner for MyWrapper {
67///     type InnerType = String;
68///
69///     fn into_inner(self) -> Self::InnerType {
70///         self.0
71///     }
72/// }
73/// ```
74///
75/// # Examples
76///
77/// ## Basic Usage
78///
79/// ```ignore
80/// use into_inner::IntoInner;
81///
82/// #[derive(IntoInner)]
83/// struct MyWrapper(String);
84///
85/// let wrapper = MyWrapper("Hello, world!".to_string());
86/// let inner = wrapper.into_inner();
87/// assert_eq!(inner, "Hello, world!");
88/// ```
89///
90/// ## Compile-Time Errors
91///
92/// The macro will generate a compile-time error if applied to a struct with multiple fields:
93///
94/// ```rust,compile_fail
95/// use into_inner::IntoInner;
96///
97/// #[derive(IntoInner)]
98/// struct InvalidWrapper(String, i32); // Error: `#[derive(IntoInner)]` supports only tuple structs with one field
99/// ```
100///
101/// Or if applied to a struct with named fields:
102///
103/// ```rust,compile_fail
104/// use into_inner::IntoInner;
105///
106/// #[derive(IntoInner)]
107/// struct NamedFieldsWrapper {
108///     field: String,
109/// } // Error: `#[derive(IntoInner)]` can only be used on tuple structs
110/// ```
111///
112/// ## Generic Tuple Structs
113///
114/// The macro also works with generic tuple structs:
115///
116/// ```ignore
117/// use into_inner::IntoInner;
118///
119/// #[derive(IntoInner)]
120/// struct GenericWrapper<T>(T);
121///
122/// let wrapper = GenericWrapper(42);
123/// let inner = wrapper.into_inner();
124/// assert_eq!(inner, 42);
125/// ```
126#[proc_macro_derive(IntoInner)]
127pub fn derive_into_inner(input: TokenStream) -> TokenStream {
128    let input = parse_macro_input!(input as DeriveInput);
129    let name = &input.ident;
130    let generics = &input.generics;
131    let (impl_generics, ty_generics, where_clause) = generics.split_for_impl();
132
133    // Verify that the struct is a tuple struct with a single field
134    let inner_type = match input.data {
135        Data::Struct(ref s) => match &s.fields {
136            Fields::Unnamed(fields) if fields.unnamed.len() == 1 => {
137                &fields.unnamed.first().unwrap().ty
138            }
139            _ => {
140                return Error::new_spanned(
141                    &s.fields,
142                    "`#[derive(IntoInner)]` supports only tuple structs with one field",
143                )
144                .to_compile_error()
145                .into();
146            }
147        },
148        _ => {
149            return Error::new_spanned(
150                &input,
151                "`#[derive(IntoInner)]` can only be used on tuple structs",
152            )
153            .to_compile_error()
154            .into();
155        }
156    };
157
158    // Generate the code for the `into_inner` method and the implementation of the `IntoInner` trait
159    let expanded = quote! {
160        impl #impl_generics #name #ty_generics #where_clause {
161            /// Consumes the struct and returns the inner value.
162            pub fn into_inner(self) -> #inner_type {
163                self.0
164            }
165        }
166
167        impl #impl_generics IntoInner for #name #ty_generics #where_clause {
168            type InnerType = #inner_type;
169
170            /// Consumes the struct and returns the inner value.
171            fn into_inner(self) -> Self::InnerType {
172                self.0
173            }
174        }
175    };
176
177    TokenStream::from(expanded)
178}