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 .unwrap_or_else(|err| {
67 let mut errors =
68 err .into_iter()
69 .map(|err| Error::new(
70 err.span(),
71 format_args!("`#[drop_with_owned_fields::drop_with_owned_fields]`: {}", err),
72 ))
73 ;
74 let mut err = errors.next().unwrap();
75 errors.for_each(|cur| err.combine(cur));
76 err.to_compile_error()
77 })
78 .into()
79}
80
81enum Input {
82 DeriveInput(DeriveInput),
83 #[cfg(feature = "drop-sugar")]
84 ItemImpl(ItemImpl),
85}
86
87impl Parse for Input {
88 fn parse(input: ParseStream<'_>) -> Result<Self> {
89 let attrs = Attribute::parse_outer(input)?;
90 if input.peek(Token![impl]) {
91 #[cfg(not(feature = "drop-sugar"))] {
92 Err(input.error("\
93 support for this kind of input requires enabling the `drop-sugar` Cargo \
94 feature, like so:\n \
95 # Cargo.toml:\n\n \
96 [dependencies]\n \
97 # ...\n \
98 drop-with-owned-fields.version = \"x.y.z\"\n \
99 drop-with-owned-fields.features = [\"drop-sugar\"]\
100 "))
101 }
102 #[cfg(feature = "drop-sugar")]
103 {
104 let mut item_impl: ItemImpl = input.parse()?;
105 item_impl.attrs = attrs;
106 Ok(Self::ItemImpl(item_impl))
107 }
108 } else {
109 let mut derive_input: DeriveInput = input.parse()?;
110 derive_input.attrs = attrs;
111 Ok(Self::DeriveInput(derive_input))
112 }
113 }
114}
115
116fn drop_with_owned_fields_impl(
117 args: TokenStream2,
118 input: TokenStream2,
119) -> Result<TokenStream2>
120{
121 let input = match parse2(input)? {
122 Input::DeriveInput(it) => it,
123 #[cfg(feature = "drop-sugar")]
124 Input::ItemImpl(item_impl) => return drop_sugar::handle(args, item_impl),
125 };
126 let ref args: args::Args = parse2(args)?;
127 let DeriveInput {
128 vis: pub_,
129 attrs,
130 ident: StructName @ _,
131 generics,
132 data,
133 } = &input;
134 let ref docs =
135 attrs
136 .iter()
137 .filter(|attr| attr.path().is_ident("doc"))
138 .collect::<Vec<_>>()
139 ;
140 let DataStruct { fields, semi_token, .. } = match *data {
141 | Data::Struct(ref it) => it,
142 | Data::Enum(DataEnum { enum_token: token::Enum { span, .. }, .. })
143 | Data::Union(DataUnion { union_token: token::Union { span, .. }, .. })
144 => {
145 return Err(Error::new(span, "expected a `struct`"));
146 },
147 };
148 fn super_of(pub_: &Visibility) -> Cow<'_, Visibility> {
149 match &*pub_ {
150 | Visibility::Public(_) => pub_.borrowed(),
151 | Visibility::Inherited => Cow::Owned(parse_quote!(pub(super))),
152 | Visibility::Restricted(VisRestricted { path, .. }) => {
153 match path.get_ident().map(ToString::to_string).as_deref() {
154 | Some("crate") => pub_.borrowed(),
155 | _ if path.leading_colon.is_some() => pub_.borrowed(),
156 | Some("self") => Cow::Owned(parse_quote!(
157 pub(super)
158 )),
159 | _ => Cow::Owned(parse_quote!(
160 pub(in super :: #path)
161 )),
162 }
163 },
164 }
165 }
166 let pub_super = super_of(pub_);
167 let fields = fields.clone().also(|fields| {
168 fields.iter_mut().for_each(|Field { vis: pub_, .. }| {
169 *pub_ = super_of(pub_).into_owned();
170 });
171 });
172
173 let pub_capped_at_crate = match &*pub_super {
174 | Visibility::Public(_) => Cow::Owned(parse_quote!(
175 pub(crate)
176 )),
177 | it => it.borrowed(),
178 };
179 let (IntroGenerics @ _, FwdGenerics @ _, where_clauses) = generics.split_for_impl();
180
181 let struct_name_helper_module = &format_ident!(
182 "_{StructName}ඞdrop_with_owned_fields"
183 );
184
185 let fields_struct_span;
186 let mut maybe_re_export = quote!();
187 let StructNameFields @ _ = match &args.maybe_rename {
188 Either::Left(RenameOfDestructuredFieldsType {
189 pub_,
190 struct_,
191 name: StructNameFields @ _,
192 }) => {
193 maybe_re_export = quote!(
194 #pub_ use #struct_name_helper_module::#StructNameFields;
195 );
196 fields_struct_span = struct_.span();
197 StructNameFields
198 },
199 Either::Right(infer) => {
200 fields_struct_span = infer.span_location();
201 &format_ident!("{StructName}ඞFields", span=fields_struct_span)
202 },
203 };
204 let struct_fields_def = quote_spanned!(fields_struct_span=>
205 #(#attrs)*
206 #pub_super
207 struct #StructNameFields #IntroGenerics
208 #where_clauses
209 #fields
210 #semi_token
211 );
212
213 let other_derives_and_attrs_hack =
214 derives::best_effort_compat_with_other_derives_and_attrs(
215 &input,
216 StructNameFields,
217 )?
218 ;
219
220 Ok(quote!(
221 #other_derives_and_attrs_hack
222
223 #[doc(inline)]
224 #(#docs)*
225 #pub_ use #struct_name_helper_module::#StructName;
226
227 #maybe_re_export
228
229 mod #struct_name_helper_module {
230 use super::*;
231
232 #struct_fields_def
233
234 #[repr(transparent)]
235 #pub_super
236 struct #StructName #IntroGenerics
237 #where_clauses
238 {
239 manually_drop_fields:
240 ::core::mem::ManuallyDrop<
241 ::drop_with_owned_fields::DestructuredFieldsOf<Self>,
242 >
243 ,
244 }
245
246 impl #IntroGenerics
247 ::core::ops::Drop
248 for
249 #StructName #FwdGenerics
250 {
251 #[inline]
252 fn drop(&mut self) {
253 <Self as ::drop_with_owned_fields::DropWithOwnedFields>::drop(
254 unsafe {
255 ::core::mem::ManuallyDrop::take(&mut self.manually_drop_fields)
256 }
257 )
258 }
259 }
260
261 impl #IntroGenerics
262 ::drop_with_owned_fields::ඞ::drop_with_owned_fields_annotation
263 for
264 #StructName #FwdGenerics
265 #where_clauses
266 {}
267
268 impl #IntroGenerics
269 ::drop_with_owned_fields::DestructureFields
270 for
271 #StructName #FwdGenerics
272 #where_clauses
273 {
274 type Fields = #StructNameFields #FwdGenerics;
275 }
276
277 impl #IntroGenerics
278 ::core::convert::From<
279 #StructNameFields #FwdGenerics,
280 >
281 for
282 #StructName #FwdGenerics
283 #where_clauses
284 {
285 #[inline]
286 fn from(this: #StructNameFields #FwdGenerics)
287 -> Self
288 {
289 this.into()
290 }
291 }
292
293 impl #IntroGenerics #StructNameFields #FwdGenerics
294 #where_clauses
295 {
296 #[inline]
297 #pub_
298 const
299 fn into(self) -> #StructName #FwdGenerics {
300 #StructName {
301 manually_drop_fields: ::core::mem::ManuallyDrop::new(
302 self,
303 ),
304 }
305 }
306 }
307
308 impl #IntroGenerics #StructName #FwdGenerics {
309 #[inline]
310 #pub_capped_at_crate
311 const
312 fn destructure_fields_disabling_impl_drop(self: #StructName #FwdGenerics)
313 -> #StructNameFields #FwdGenerics
314 {
315 let this = ::core::mem::ManuallyDrop::new(self);
317 unsafe {
318 ::core::mem::ManuallyDrop::into_inner(
326 ::drop_with_owned_fields::ඞ::ConstTransmuteUnchecked::<
327 #StructName #FwdGenerics,
328 #StructNameFields #FwdGenerics,
329 >
330 {
331 src: this,
332 }
333 .dst
334 )
335 }
336 }
337 }
338
339 impl #IntroGenerics
341 ::core::ops::Deref
342 for
343 #StructName #FwdGenerics
344 #where_clauses
345 {
346 type Target = ::drop_with_owned_fields::DestructuredFieldsOf<Self>;
347
348 #[inline]
349 fn deref(&self) -> &Self::Target {
350 &*self.manually_drop_fields
351 }
352 }
353 impl #IntroGenerics
354 ::core::ops::DerefMut
355 for
356 #StructName #FwdGenerics
357 #where_clauses
358 {
359 #[inline]
360 fn deref_mut(&mut self) -> &mut Self::Target {
361 &mut *self.manually_drop_fields
362 }
363 }
364 }
365 ))
366}