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