ouroboros_macro/generate/
into_heads.rs
1use proc_macro2::TokenStream;
2use quote::quote;
3
4use crate::info_structures::{Options, StructInfo};
5
6pub fn make_into_heads(info: &StructInfo, options: Options) -> (TokenStream, TokenStream) {
8 let visibility = if options.do_pub_extras {
9 info.vis.clone()
10 } else {
11 syn::parse_quote! { pub(super) }
12 };
13 let mut code = Vec::new();
14 let mut field_initializers = Vec::new();
15 let mut head_fields = Vec::new();
16 let internal_struct = &info.internal_ident;
17 for field in info.fields.iter().rev() {
20 let field_name = &field.name;
21 if field.self_referencing {
22 code.push(quote! { ::core::mem::drop(this.#field_name); });
24 } else {
25 code.push(quote! { let #field_name = this.#field_name; });
26 if field.is_borrowed() {
27 field_initializers
28 .push(quote! { #field_name: ::ouroboros::macro_help::unbox(#field_name) });
29 } else {
30 field_initializers.push(quote! { #field_name });
31 }
32 let field_type = &field.typ;
33 head_fields.push(quote! { #visibility #field_name: #field_type });
34 }
35 }
36 for (ty, ident) in info.generic_consumers() {
37 head_fields.push(quote! { #ident: ::core::marker::PhantomData<#ty> });
38 field_initializers.push(quote! { #ident: ::core::marker::PhantomData });
39 }
40 let documentation = format!(
41 concat!(
42 "A struct which contains only the ",
43 "[head fields](https://docs.rs/ouroboros/latest/ouroboros/attr.self_referencing.html#definitions) of [`{0}`]({0})."
44 ),
45 info.ident.to_string()
46 );
47 let generic_params = info.generic_params();
48 let generic_where = &info.generics.where_clause;
49 let heads_struct_def = quote! {
50 #[doc=#documentation]
51 #visibility struct Heads <#generic_params> #generic_where {
52 #(#head_fields),*
53 }
54 };
55 let documentation = concat!(
56 "This function drops all internally referencing fields and returns only the ",
57 "[head fields](https://docs.rs/ouroboros/latest/ouroboros/attr.self_referencing.html#definitions) of this struct."
58 ).to_owned();
59
60 let documentation = if !options.do_no_doc {
61 quote! {
62 #[doc=#documentation]
63 }
64 } else {
65 quote! { #[doc(hidden)] }
66 };
67
68 let generic_args = info.generic_arguments();
69 let into_heads_fn = quote! {
70 #documentation
71 #[allow(clippy::drop_ref)]
72 #[allow(clippy::drop_copy)]
73 #[allow(clippy::drop_non_drop)]
74 #visibility fn into_heads(self) -> Heads<#(#generic_args),*> {
75 let this_ptr = &self as *const _;
76 let this: #internal_struct<#(#generic_args),*> = unsafe { ::core::mem::transmute_copy(&*this_ptr) };
77 ::core::mem::forget(self);
78 #(#code)*
79 Heads {
80 #(#field_initializers),*
81 }
82 }
83 };
84 (heads_struct_def, into_heads_fn)
85}