drop_with_owned_fields_proc_macros/
_mod.rs1#![allow(nonstandard_style, unused_imports, unused_braces)]
5
6use ::core::{
7 mem,
8 ops::Not as _,
9};
10use std::borrow::Cow;
11use ::proc_macro::{
12 TokenStream,
13};
14use ::proc_macro2::{
15 Span,
16 TokenStream as TokenStream2,
17 TokenTree as TT,
18};
19use quote::quote_spanned;
20use ::quote::{
21 format_ident,
22 ToTokens,
23};
24use ::syn::{*,
25 parse::{Parse, Parser, ParseStream},
26 punctuated::Punctuated,
27 Result, spanned::Spanned,
29};
30use self::utils::default_to_mixed_site_span::{
31 quote, parse_quote, SpanLocationExt as _,
32};
33
34#[macro_use]
35#[path = "utils/_mod.rs"]
36mod utils;
37use utils::{BorrowedExt, Retain};
38
39mod args;
40
41mod derives;
42
43#[cfg(feature = "drop-sugar")]
44mod drop_sugar;
45
46#[proc_macro_attribute] pub
47fn ඞannihilate(
48 _: TokenStream,
49 _: TokenStream,
50) -> TokenStream {
51 TokenStream::new()
52}
53
54#[proc_macro_attribute] pub
56fn drop_with_owned_fields(
57 args: TokenStream,
58 input: TokenStream,
59) -> TokenStream
60{
61 drop_with_owned_fields_impl(args.into(), input.into())
62 .unwrap_or_else(|err| {
64 let mut errors =
65 err .into_iter()
66 .map(|err| Error::new(
67 err.span(),
68 format_args!("`#[drop_with_owned_fields::drop_with_owned_fields]`: {}", err),
69 ))
70 ;
71 let mut err = errors.next().unwrap();
72 errors.for_each(|cur| err.combine(cur));
73 err.to_compile_error()
74 })
75 .into()
76}
77
78enum Input {
79 DeriveInput(DeriveInput),
80 #[cfg(feature = "drop-sugar")]
81 ItemImpl(ItemImpl),
82}
83
84impl Parse for Input {
85 fn parse(input: ParseStream<'_>) -> Result<Self> {
86 let attrs = Attribute::parse_outer(input)?;
87 if input.peek(Token![impl]) {
88 #[cfg(not(feature = "drop-sugar"))] {
89 Err(input.error("\
90 support for this kind of input requires enabling the `drop-sugar` Cargo \
91 feature, like so:\n \
92 # Cargo.toml:\n\n \
93 [dependencies]\n \
94 # ...\n \
95 drop-with-owned-fields.version = \"x.y.z\"\n \
96 drop-with-owned-fields.features = [\"drop-sugar\"]\
97 "))
98 }
99 #[cfg(feature = "drop-sugar")]
100 {
101 let mut item_impl: ItemImpl = input.parse()?;
102 item_impl.attrs = attrs;
103 Ok(Self::ItemImpl(item_impl))
104 }
105 } else {
106 let mut derive_input: DeriveInput = input.parse()?;
107 derive_input.attrs = attrs;
108 Ok(Self::DeriveInput(derive_input))
109 }
110 }
111}
112
113fn drop_with_owned_fields_impl(
114 args: TokenStream2,
115 input: TokenStream2,
116) -> Result<TokenStream2>
117{
118 let input = match parse2(input)? {
119 Input::DeriveInput(it) => it,
120 #[cfg(feature = "drop-sugar")]
121 Input::ItemImpl(item_impl) => return drop_sugar::handle(args, item_impl),
122 };
123 let args: args::Args = parse2(args)?;
124 let DeriveInput {
125 vis: pub_,
126 attrs,
127 ident: StructName @ _,
128 generics,
129 data,
130 } = &input;
131 let ref docs =
132 attrs
133 .iter()
134 .filter(|attr| attr.path().is_ident("doc"))
135 .collect::<Vec<_>>()
136 ;
137 let DataStruct { fields, semi_token, .. } = match *data {
138 | Data::Struct(ref it) => it,
139 | Data::Enum(DataEnum { enum_token: token::Enum { span, .. }, .. })
140 | Data::Union(DataUnion { union_token: token::Union { span, .. }, .. })
141 => {
142 return Err(Error::new(span, "expected a `struct`"));
143 },
144 };
145 let pub_super = match &*pub_ {
146 | Visibility::Public(_) => pub_.borrowed(),
147 | Visibility::Inherited => Cow::Owned(parse_quote!(pub(super))),
148 | Visibility::Restricted(VisRestricted { path, .. }) => {
149 match path.get_ident().map(ToString::to_string).as_deref() {
150 | Some("crate")
151 | _ if path.leading_colon.is_some()
152 => {
153 pub_.borrowed()
154 },
155 | Some("self") => Cow::Owned(parse_quote!(
156 pub(super)
157 )),
158 | _ => Cow::Owned(parse_quote!(
159 pub(in super :: #path)
160 )),
161 }
162 },
163 };
164 let pub_capped_at_crate = match &*pub_ {
165 | Visibility::Public(_) => Cow::Owned(parse_quote!(
166 pub(crate)
167 )),
168 | _ => pub_.borrowed(),
169 };
170 let (IntroGenerics @ _, FwdGenerics @ _, where_clauses) = generics.split_for_impl();
171
172 let fields_struct_pub;
173 let fields_struct_span;
174 let mut maybe_doc_hidden = quote!();
175 let StructNameDestructuredFields @ _ = if let Some(rename) = &args.maybe_rename {
176 fields_struct_pub = &rename.pub_;
177 fields_struct_span = rename.type_.span();
178 &rename.name
179 } else {
180 maybe_doc_hidden = quote!(#[doc(hidden)]);
181 fields_struct_pub = pub_;
182 fields_struct_span = Span::mixed_site();
183 &format_ident!("{StructName}ඞDestructuredFields")
184 };
185 let struct_fields_def = quote_spanned!(fields_struct_span=>
186 #maybe_doc_hidden
187 #(#attrs)*
188 #fields_struct_pub
189 struct #StructNameDestructuredFields #IntroGenerics
190 #where_clauses
191 #fields
192 #semi_token
193 );
194
195 let struct_name_helper_module = &format_ident!(
196 "_{StructName}ඞdrop_with_owned_fields"
197 );
198
199 let other_derives_and_attrs_hack =
200 derives::best_effort_compat_with_other_derives_and_attrs(
201 &input,
202 StructNameDestructuredFields,
203 )?
204 ;
205
206 Ok(quote!(
207 #other_derives_and_attrs_hack
208
209 #struct_fields_def
210
211 #[doc(inline)]
212 #(#docs)*
213 #pub_ use #struct_name_helper_module::#StructName;
214
215 mod #struct_name_helper_module {
216 use super::*;
217
218 #[repr(transparent)]
219 #pub_super
220 struct #StructName #IntroGenerics
221 #where_clauses
222 {
223 manually_drop_fields:
224 ::core::mem::ManuallyDrop<
225 ::drop_with_owned_fields::DestructuredFieldsOf<Self>,
226 >
227 ,
228 }
229
230 impl #IntroGenerics
231 ::core::ops::Drop
232 for
233 #StructName #FwdGenerics
234 {
235 #[inline]
236 fn drop(&mut self) {
237 <Self as ::drop_with_owned_fields::DropWithOwnedFields>::drop(
238 unsafe {
239 ::core::mem::ManuallyDrop::take(&mut self.manually_drop_fields)
240 }
241 )
242 }
243 }
244
245 impl #IntroGenerics
246 ::drop_with_owned_fields::ඞ::drop_with_owned_fields_annotation
247 for
248 #StructName #FwdGenerics
249 #where_clauses
250 {}
251
252 impl #IntroGenerics
253 ::drop_with_owned_fields::DestructureFields
254 for
255 #StructName #FwdGenerics
256 #where_clauses
257 {
258 type DestructuredFields = #StructNameDestructuredFields #FwdGenerics;
259
260 #[inline]
261 fn destructure_fields_disabling_extra_drop(self)
262 -> Self::DestructuredFields
263 {
264 #![deny(unconditional_recursion)]
265 Self::destructure_fields_disabling_extra_drop(self)
266 }
267 }
268
269 impl #IntroGenerics
270 ::core::convert::From<
271 #StructNameDestructuredFields #FwdGenerics,
272 >
273 for
274 #StructName #FwdGenerics
275 #where_clauses
276 {
277 #[inline]
278 fn from(this: #StructNameDestructuredFields #FwdGenerics)
279 -> Self
280 {
281 this.into()
282 }
283 }
284
285 impl #IntroGenerics #StructNameDestructuredFields #FwdGenerics
286 #where_clauses
287 {
288 #[inline]
289 #pub_
290 const
291 fn into(self) -> #StructName #FwdGenerics {
292 #StructName {
293 manually_drop_fields: ::core::mem::ManuallyDrop::new(
294 self,
295 ),
296 }
297 }
298 }
299
300 impl #IntroGenerics #StructName #FwdGenerics {
301 #[inline]
302 #pub_capped_at_crate
303 const
304 fn destructure_fields_disabling_extra_drop(self: #StructName #FwdGenerics)
305 -> #StructNameDestructuredFields #FwdGenerics
306 {
307 let this = ::core::mem::ManuallyDrop::new(self);
309 unsafe {
310 ::core::mem::ManuallyDrop::into_inner(
318 ::drop_with_owned_fields::ඞ::ConstTransmuteUnchecked::<
319 #StructName #FwdGenerics,
320 #StructNameDestructuredFields #FwdGenerics,
321 >
322 {
323 src: this,
324 }
325 .dst
326 )
327 }
328 }
329 }
330
331 impl #IntroGenerics
333 ::core::ops::Deref
334 for
335 #StructName #FwdGenerics
336 #where_clauses
337 {
338 type Target = ::drop_with_owned_fields::DestructuredFieldsOf<Self>;
339
340 #[inline]
341 fn deref(&self) -> &Self::Target {
342 &*self.manually_drop_fields
343 }
344 }
345 impl #IntroGenerics
346 ::core::ops::DerefMut
347 for
348 #StructName #FwdGenerics
349 #where_clauses
350 {
351 #[inline]
352 fn deref_mut(&mut self) -> &mut Self::Target {
353 &mut *self.manually_drop_fields
354 }
355 }
356 }
357 ))
358}