ouroboros_macro/generate/
with.rs
1use crate::info_structures::{FieldType, Options, StructInfo};
2use proc_macro2::{Span, TokenStream};
3use quote::quote;
4use syn::{Error, Lifetime, WhereClause};
5
6pub fn make_with_all_function(
7 info: &StructInfo,
8 options: Options,
9) -> Result<(TokenStream, TokenStream), Error> {
10 let visibility = if options.do_pub_extras {
11 info.vis.clone()
12 } else {
13 syn::parse_quote! { pub(super) }
14 };
15 let mut fields = Vec::new();
16 let mut field_assignments = Vec::new();
17 for field in info.fields.iter().rev() {
19 let field_name = &field.name;
20 let field_type = &field.typ;
21 if field.field_type == FieldType::Tail {
22 fields.push(quote! { #visibility #field_name: &'outer_borrow #field_type });
23 field_assignments.push(quote! { #field_name: &this.#field_name });
24 } else if field.field_type == FieldType::Borrowed {
25 let ass = quote! { #field_name: unsafe {
26 ::ouroboros::macro_help::change_lifetime(
27 &*this.#field_name
28 )
29 } };
30 fields.push(quote! { #visibility #field_name: &'this #field_type });
31 field_assignments.push(ass.clone());
32 } else if field.field_type == FieldType::BorrowedMut {
33 }
36 }
37
38 for (ty, ident) in info.generic_consumers() {
39 fields.push(quote! { #ident: ::core::marker::PhantomData<#ty> });
40 field_assignments.push(quote! { #ident: ::core::marker::PhantomData });
41 }
42 let new_generic_params = info.borrowed_generic_params();
43 let new_generic_args = info.borrowed_generic_arguments();
44
45 let struct_documentation = format!(
46 concat!(
47 "A struct for holding immutable references to all ",
48 "[tail and immutably borrowed fields](https://docs.rs/ouroboros/latest/ouroboros/attr.self_referencing.html#definitions) in an instance of ",
49 "[`{0}`]({0})."
50 ),
51 info.ident.to_string()
52 );
53 let ltname = format!("'{}", info.fake_lifetime());
54 let lifetime = Lifetime::new(<name, Span::call_site());
55 let generic_where = if let Some(clause) = &info.generics.where_clause {
56 let mut clause = clause.clone();
57 let extra: WhereClause = syn::parse_quote! { where #lifetime: 'this };
58 clause
59 .predicates
60 .push(extra.predicates.first().unwrap().clone());
61 let extra: WhereClause = syn::parse_quote! { where 'this: 'outer_borrow };
62 clause
63 .predicates
64 .push(extra.predicates.first().unwrap().clone());
65 clause
66 } else {
67 syn::parse_quote! { where #lifetime: 'this, 'this: 'outer_borrow }
68 };
69 let struct_defs = quote! {
70 #[doc=#struct_documentation]
71 #visibility struct BorrowedFields #new_generic_params #generic_where { #(#fields),* }
72 };
73 let borrowed_fields_type = quote! { BorrowedFields<#(#new_generic_args),*> };
74 let documentation = concat!(
75 "This method provides immutable references to all ",
76 "[tail and immutably borrowed fields](https://docs.rs/ouroboros/latest/ouroboros/attr.self_referencing.html#definitions).",
77 );
78 let documentation = if !options.do_no_doc {
79 quote! {
80 #[doc=#documentation]
81 }
82 } else {
83 quote! { #[doc(hidden)] }
84 };
85 let fn_defs = quote! {
86 #documentation
87 #[inline(always)]
88 #visibility fn with <'outer_borrow, ReturnType>(
89 &'outer_borrow self,
90 user: impl for<'this> ::core::ops::FnOnce(#borrowed_fields_type) -> ReturnType
91 ) -> ReturnType {
92 let this = unsafe { self.actual_data.assume_init_ref() };
93 user(BorrowedFields {
94 #(#field_assignments),*
95 })
96 }
97 };
98 Ok((struct_defs, fn_defs))
99}