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}