ouroboros_macro/generate/
struc.rs

1use crate::{
2    info_structures::StructInfo,
3    utils::{self, replace_this_with_lifetime},
4};
5use proc_macro2::TokenStream;
6use quote::quote;
7use syn::Error;
8
9/// Creates the struct that will actually store the data.
10pub fn create_actual_struct_def(info: &StructInfo) -> Result<TokenStream, Error> {
11    let visibility = utils::submodule_contents_visibility(&info.vis);
12    let mut fields = Vec::new();
13    for (ty, ident) in info.generic_consumers() {
14        fields.push(quote! { #ident: ::core::marker::PhantomData<#ty> });
15    }
16    let generic_params = info.generic_params();
17    let generic_args = info.generic_arguments();
18    let generic_where = &info.generics.where_clause;
19    let ident = &info.ident;
20    let internal_ident = &info.internal_ident;
21    Ok(quote! {
22        #[repr(transparent)]
23        #visibility struct #ident <#generic_params> #generic_where {
24            actual_data: ::core::mem::MaybeUninit<#internal_ident<#(#generic_args),*>>,
25        }
26    })
27}
28
29/// Creates a struct with fields like the original struct. Instances of the
30/// "actual" struct are reinterpreted as instances of the "internal" struct
31/// whenever data needs to be accessed. (This gets around the problem that
32/// references passed to functions must be valid through the entire function,
33/// but references *created* inside a function can be considered invalid
34/// whenever, even during the duration of the function.)
35pub fn create_internal_struct_def(info: &StructInfo) -> Result<TokenStream, Error> {
36    let ident = &info.internal_ident;
37    let generics = &info.generics;
38
39    let field_defs: Vec<_> = info
40        .fields
41        .iter()
42        // Reverse the order of all fields. We ensure that items in the struct are only dependent
43        // on references to items above them. Rust drops items in a struct in forward declaration order.
44        // This would cause parents being dropped before children, necessitating the reversal.
45        .rev()
46        .map(|field| {
47            let name = &field.name;
48            let ty = field.stored_type();
49            quote! {
50                #[doc(hidden)]
51                #name: #ty
52            }
53        })
54        .collect();
55
56    // Create the new struct definition.
57    let mut where_clause = quote! {};
58    if let Some(clause) = &generics.where_clause {
59        where_clause = quote! { #clause };
60    }
61    let def = quote! {
62        struct #ident #generics #where_clause {
63            #(#field_defs),*
64        }
65    };
66
67    // Finally, replace the fake 'this lifetime with the one we found.
68    let fake_lifetime = info.fake_lifetime();
69    let def = replace_this_with_lifetime(quote! { #def }, fake_lifetime.clone());
70
71    Ok(def)
72}