1 #![recursion_limit = "512"]
2
3 extern crate proc_macro;
4 extern crate proc_macro2;
5 #[macro_use]
6 extern crate syn;
7 #[macro_use]
8 extern crate quote;
9
10 use std::iter::{self, FromIterator};
11 use syn::spanned::Spanned;
12 use syn::visit::Visit;
13 use syn::fold::Fold;
14 use quote::ToTokens;
15 use proc_macro2::Span;
16
17
18 /// From `procedural_masquerade` crate
19 #[doc(hidden)]
_extract_input(derive_input: &str) -> &str20 fn _extract_input(derive_input: &str) -> &str {
21 let mut input = derive_input;
22
23 for expected in &["#[allow(unused)]", "enum", "ProceduralMasqueradeDummyType", "{", "Input", "=", "(0,", "stringify!", "("] {
24 input = input.trim_start();
25 assert!(input.starts_with(expected), "expected prefix {:?} not found in {:?}", expected, derive_input);
26 input = &input[expected.len()..];
27 }
28
29 for expected in [")", ").0,", "}"].iter().rev() {
30 input = input.trim_end();
31 assert!(input.ends_with(expected), "expected suffix {:?} not found in {:?}", expected, derive_input);
32 let end = input.len() - expected.len();
33 input = &input[..end];
34 }
35
36 input
37 }
38
39
40 #[doc(hidden)]
41 #[allow(non_snake_case)]
42 #[proc_macro_derive(__rental_traits)]
__rental_traits(input: proc_macro::TokenStream) -> proc_macro::TokenStream43 pub fn __rental_traits(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
44 let mut tokens = proc_macro2::TokenStream::new();
45
46 let max_arity = _extract_input(&input.to_string()).parse::<usize>().expect("Input must be an integer literal.");
47 write_rental_traits(&mut tokens, max_arity);
48
49 tokens.into()
50 }
51
52
53 #[doc(hidden)]
54 #[allow(non_snake_case)]
55 #[proc_macro_derive(__rental_structs_and_impls)]
__rental_structs_and_impls(input: proc_macro::TokenStream) -> proc_macro::TokenStream56 pub fn __rental_structs_and_impls(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
57 let mut tokens = proc_macro2::TokenStream::new();
58
59 for item in syn::parse_str::<syn::File>(_extract_input(&input.to_string())).expect("Failed to parse items in module body.").items.iter() {
60 match *item {
61 syn::Item::Use(..) => {
62 item.to_tokens(&mut tokens);
63 },
64 syn::Item::Type(..) => {
65 item.to_tokens(&mut tokens);
66 },
67 syn::Item::Struct(ref struct_info) => {
68 write_rental_struct_and_impls(&mut tokens, &struct_info);
69 },
70 _ => panic!("Item must be a `use` or `struct`."),
71 }
72 }
73
74 tokens.into()
75 }
76
77
write_rental_traits(tokens: &mut proc_macro2::TokenStream, max_arity: usize)78 fn write_rental_traits(tokens: &mut proc_macro2::TokenStream, max_arity: usize) {
79 let call_site: Span = Span::call_site();
80
81 let mut lt_params = vec![syn::LifetimeDef::new(syn::Lifetime::new("'a0", call_site))];
82
83 for arity in 2 .. max_arity + 1 {
84 let trait_ident = &syn::Ident::new(&format!("Rental{}", arity), call_site);
85 let lt_param = syn::LifetimeDef::new(syn::Lifetime::new(&format!("'a{}", arity - 1), call_site));
86 lt_params[arity - 2].bounds.push(lt_param.lifetime.clone());
87 lt_params.push(lt_param);
88
89 let lt_params_iter = <_params;
90 quote!(
91 #[doc(hidden)]
92 pub unsafe trait #trait_ident<#(#lt_params_iter),*> {
93 type Borrow;
94 type BorrowMut;
95 }
96 ).to_tokens(tokens);
97 }
98 }
99
100
write_rental_struct_and_impls(tokens: &mut proc_macro2::TokenStream, struct_info: &syn::ItemStruct)101 fn write_rental_struct_and_impls(tokens: &mut proc_macro2::TokenStream, struct_info: &syn::ItemStruct) {
102 let def_site: Span = Span::call_site(); // FIXME: hygiene
103 let call_site: Span = Span::call_site();
104
105 if let syn::Visibility::Inherited = struct_info.vis {
106 panic!("Struct `{}` must be non-private.", struct_info.ident);
107 }
108
109 let attribs = get_struct_attribs(struct_info);
110 let (fields, fields_brace) = prepare_fields(struct_info);
111
112 let struct_generics = &struct_info.generics;
113 let struct_rlt_args = &fields.iter().fold(Vec::new(), |mut rlt_args, field| { rlt_args.extend(field.self_rlt_args.iter()); rlt_args });
114 if let Some(collide) = struct_rlt_args.iter().find(|rlt_arg| struct_generics.lifetimes().any(|lt_def| lt_def.lifetime == ***rlt_arg)) {
115 panic!("Struct `{}` lifetime parameter `{}` collides with rental lifetime.", struct_info.ident, collide);
116 }
117 let last_rlt_arg = &struct_rlt_args[struct_rlt_args.len() - 1];
118 let static_rlt_args = &iter::repeat(syn::Lifetime::new("'static", def_site)).take(struct_rlt_args.len()).collect::<Vec<_>>();
119 let self_rlt_args = &iter::repeat(syn::Lifetime::new("'__s", def_site)).take(struct_rlt_args.len()).collect::<Vec<_>>();
120
121 let item_ident = &struct_info.ident;
122 let item_vis = &struct_info.vis;
123 let item_ident_str = syn::LitStr::new(&item_ident.to_string(), item_ident.span());
124
125 let (struct_impl_params, struct_impl_args, struct_where_clause) = struct_generics.split_for_impl();
126 let where_extra = if let Some(ref struct_where_clause) = struct_where_clause {
127 if struct_where_clause.predicates.is_empty() {
128 quote!(where)
129 } else if struct_where_clause.predicates.trailing_punct() {
130 quote!()
131 } else {
132 quote!(,)
133 }
134 } else {
135 quote!(where)
136 };
137 let struct_lt_params = &struct_generics.lifetimes().collect::<Vec<_>>();
138 let struct_nonlt_params = &struct_generics.params.iter().filter(|param| if let syn::GenericParam::Lifetime(..) = **param { false } else { true }).collect::<Vec<_>>();
139 let struct_lt_args = &struct_lt_params.iter().map(|lt_def| <_def.lifetime).collect::<Vec<_>>();
140
141 let struct_nonlt_args = &struct_nonlt_params.iter().map(|param| match **param {
142 syn::GenericParam::Type(ref ty) => &ty.ident,
143 syn::GenericParam::Const(ref co) => &co.ident,
144 syn::GenericParam::Lifetime(..) => unreachable!(),
145 }).collect::<Vec<_>>();
146
147 let rental_trait_ident = syn::Ident::new(&format!("Rental{}", struct_rlt_args.len()), def_site);
148 let field_idents = &fields.iter().map(|field| &field.name).collect::<Vec<_>>();
149 let local_idents = field_idents;
150 let field_ident_strs = &field_idents.iter().map(|ident| syn::LitStr::new(&ident.to_string(), ident.span())).collect::<Vec<_>>();
151
152 let (ref self_ref_param, ref self_lt_ref_param, ref self_mut_param, ref self_move_param, ref self_arg) = if attribs.is_deref_suffix {
153 (quote!(_self: &Self), quote!(_self: &'__s Self), quote!(_self: &mut Self), quote!(_self: Self), quote!(_self))
154 } else {
155 (quote!(&self), quote!(&'__s self), quote!(&mut self), quote!(self), quote!(self))
156 };
157
158 let borrow_ident = syn::Ident::new(&(struct_info.ident.to_string() + "_Borrow"), call_site);
159 let borrow_mut_ident = syn::Ident::new(&(struct_info.ident.to_string() + "_BorrowMut"), call_site);
160 let borrow_quotes = &make_borrow_quotes(self_arg, &fields, attribs.is_rental_mut);
161 let borrow_tys = &borrow_quotes.iter().map(|&BorrowQuotes{ref ty, ..}| ty).collect::<Vec<_>>();
162 let borrow_ty_hacks = &borrow_quotes.iter().map(|&BorrowQuotes{ref ty_hack, ..}| ty_hack).collect::<Vec<_>>();
163 let borrow_suffix_ty = &borrow_tys[fields.len() - 1];
164 let borrow_exprs = &borrow_quotes.iter().map(|&BorrowQuotes{ref expr, ..}| expr).collect::<Vec<_>>();
165 let borrow_suffix_expr = &borrow_exprs[fields.len() - 1];
166 let borrow_mut_tys = &borrow_quotes.iter().map(|&BorrowQuotes{ref mut_ty, ..}| mut_ty).collect::<Vec<_>>();
167 let borrow_mut_ty_hacks = &borrow_quotes.iter().map(|&BorrowQuotes{ref mut_ty_hack, ..}| mut_ty_hack).collect::<Vec<_>>();
168 let borrow_mut_suffix_ty = &borrow_mut_tys[fields.len() - 1];
169 let borrow_mut_exprs = &borrow_quotes.iter().map(|&BorrowQuotes{ref mut_expr, ..}| mut_expr).collect::<Vec<_>>();
170 let borrow_mut_suffix_expr = &borrow_mut_exprs[fields.len() - 1];
171
172 let struct_rlt_params = &struct_rlt_args.iter().zip(struct_rlt_args.iter().skip(1)).map(|(rlt_arg, next_rlt_arg)| {
173 syn::LifetimeDef {
174 attrs: Vec::with_capacity(0),
175 lifetime: (*rlt_arg).clone(),
176 bounds: vec![(*next_rlt_arg).clone()].into_iter().collect(),
177 colon_token: Default::default(),
178 }
179 }).chain(Some(syn::LifetimeDef {
180 attrs: Vec::with_capacity(0),
181 lifetime: struct_rlt_args[struct_rlt_args.len() - 1].clone(),
182 bounds: syn::punctuated::Punctuated::new(),
183 colon_token: Default::default(),
184 })).collect::<Vec<_>>();
185
186 let borrow_lt_params = &struct_rlt_params.iter().cloned()
187 .chain( struct_lt_params.iter().map(|lt_def| {
188 let mut lt_def = (*lt_def).clone();
189 lt_def.bounds.push(struct_rlt_args[0].clone());
190 lt_def
191 })).collect::<Vec<_>>();
192
193 let field_tys = &fields.iter().map(|field| &field.erased.ty).collect::<Vec<_>>();
194 let head_ident = &local_idents[0];
195 let head_ident_rep = &iter::repeat(&head_ident).take(fields.len() - 1).collect::<Vec<_>>();
196 let head_ty = &fields[0].orig_ty;
197 let tail_tys = &field_tys.iter().skip(1).collect::<Vec<_>>();
198 let tail_idents = &local_idents.iter().skip(1).collect::<Vec<_>>();
199 let tail_closure_tys = &fields.iter().skip(1).map(|field| syn::Ident::new(&format!("__F{}", field.name), call_site)).collect::<Vec<_>>();
200 let tail_closure_quotes = make_tail_closure_quotes(&fields, borrow_quotes, attribs.is_rental_mut);
201 let tail_closure_bounds = &tail_closure_quotes.iter().map(|&ClosureQuotes{ref bound, ..}| bound).collect::<Vec<_>>();
202 let tail_closure_exprs = &tail_closure_quotes.iter().map(|&ClosureQuotes{ref expr, ..}| expr).collect::<Vec<_>>();
203 let tail_try_closure_bounds = &tail_closure_quotes.iter().map(|&ClosureQuotes{ref try_bound, ..}| try_bound).collect::<Vec<_>>();
204 let tail_try_closure_exprs = &tail_closure_quotes.iter().map(|&ClosureQuotes{ref try_expr, ..}| try_expr).collect::<Vec<_>>();
205 let suffix_ident = &field_idents[fields.len() - 1];
206 let suffix_ty = &fields[fields.len() - 1].erased.ty;
207 let suffix_rlt_args = &fields[fields.len() - 1].self_rlt_args.iter().chain(fields[fields.len() - 1].used_rlt_args.iter()).collect::<Vec<_>>();
208 let suffix_ident_str = syn::LitStr::new(&suffix_ident.to_string(), suffix_ident.span());
209 let suffix_orig_ty = &fields[fields.len() - 1].orig_ty;
210
211 let rstruct = syn::ItemStruct{
212 ident: struct_info.ident.clone(),
213 vis: item_vis.clone(),
214 attrs: attribs.doc.clone(),
215 fields: syn::Fields::Named(syn::FieldsNamed{
216 brace_token: fields_brace,
217 named: fields.iter().enumerate().map(|(i, field)| {
218 let mut field_erased = field.erased.clone();
219 if i < fields.len() - 1 {
220 field_erased.attrs.push(parse_quote!(#[allow(dead_code)]));
221 }
222 field_erased
223 }).rev().collect(),
224 }),
225 generics: struct_info.generics.clone(),
226 struct_token: struct_info.struct_token,
227 semi_token: None,
228 };
229
230 let borrow_struct = syn::ItemStruct{
231 ident: borrow_ident.clone(),
232 vis: item_vis.clone(),
233 attrs: Vec::with_capacity(0),
234 fields: syn::Fields::Named(syn::FieldsNamed{
235 brace_token: Default::default(),
236 named: fields.iter().zip(borrow_tys).enumerate().map(|(idx, (field, borrow_ty))| {
237 let mut field = field.erased.clone();
238 field.vis = if !attribs.is_rental_mut || idx == fields.len() - 1 { item_vis.clone() } else { syn::Visibility::Inherited };
239 field.ty = syn::parse::<syn::Type>((**borrow_ty).clone().into()).unwrap();
240 field
241 }).collect(),
242 }),
243 generics: {
244 let mut gen = struct_generics.clone();
245 let params = borrow_lt_params.iter().map(|lt| syn::GenericParam::Lifetime(lt.clone()))
246 .chain(gen.type_params().map(|p| syn::GenericParam::Type(p.clone())))
247 .chain(gen.const_params().map(|p| syn::GenericParam::Const(p.clone())))
248 .collect();
249 gen.params = params;
250 gen
251 },
252 struct_token: Default::default(),
253 semi_token: None,
254 };
255
256 let borrow_mut_struct = syn::ItemStruct{
257 ident: borrow_mut_ident.clone(),
258 vis: item_vis.clone(),
259 attrs: Vec::with_capacity(0),
260 fields: syn::Fields::Named(syn::FieldsNamed{
261 brace_token: Default::default(),
262 named: fields.iter().zip(borrow_mut_tys).enumerate().map(|(idx, (field, borrow_mut_ty))| {
263 let mut field = field.erased.clone();
264 field.vis = if idx == fields.len() - 1 || !attribs.is_rental_mut { (*item_vis).clone() } else { syn::Visibility::Inherited };
265 field.ty = syn::parse::<syn::Type>((**borrow_mut_ty).clone().into()).unwrap();
266 field
267 }).collect(),
268 }),
269 generics: {
270 let mut gen = struct_generics.clone();
271 let params = borrow_lt_params.iter().map(|lt| syn::GenericParam::Lifetime(lt.clone()))
272 .chain(gen.type_params().map(|p| syn::GenericParam::Type(p.clone())))
273 .chain(gen.const_params().map(|p| syn::GenericParam::Const(p.clone())))
274 .collect();
275 gen.params = params;
276 gen
277 },
278 struct_token: Default::default(),
279 semi_token: None,
280 };
281
282 let prefix_tys = &fields.iter().map(|field| &field.erased.ty).take(fields.len() - 1).collect::<Vec<_>>();
283 let static_assert_prefix_stable_derefs = &prefix_tys.iter().map(|field| {
284 if attribs.is_rental_mut {
285 quote_spanned!(field.span()/*.resolved_at(def_site)*/ => __rental_prelude::static_assert_mut_stable_deref::<#field>();)
286 } else {
287 quote_spanned!(field.span()/*.resolved_at(def_site)*/ => __rental_prelude::static_assert_stable_deref::<#field>();)
288 }
289 }).collect::<Vec<_>>();
290 let prefix_clone_traits = iter::repeat(quote!(__rental_prelude::CloneStableDeref)).take(prefix_tys.len());
291
292 let struct_span = struct_info.span()/*.resolved_at(def_site)*/;
293 let suffix_ty_span = suffix_ty.span()/*.resolved_at(def_site)*/;
294
295 quote_spanned!(struct_span =>
296 #rstruct
297
298 /// Shared borrow of a rental struct.
299 #[allow(non_camel_case_types, non_snake_case, dead_code)]
300 #borrow_struct
301
302 /// Mutable borrow of a rental struct.
303 #[allow(non_camel_case_types, non_snake_case, dead_code)]
304 #borrow_mut_struct
305 ).to_tokens(tokens);
306
307 quote_spanned!(struct_span =>
308 #[allow(dead_code)]
309 impl<#(#borrow_lt_params,)* #(#struct_nonlt_params),*> #borrow_ident<#(#struct_rlt_args,)* #(#struct_lt_args,)* #(#struct_nonlt_args),*> #struct_where_clause {
310 fn unify_tys_hack(#(#local_idents: #borrow_ty_hacks),*) -> #borrow_ident<#(#struct_rlt_args,)* #(#struct_lt_args,)* #(#struct_nonlt_args),*> {
311 #borrow_ident {
312 #(#field_idents: #local_idents,)*
313 }
314 }
315 }
316 ).to_tokens(tokens);
317
318 quote_spanned!(struct_span =>
319 #[allow(dead_code)]
320 impl<#(#borrow_lt_params,)* #(#struct_nonlt_params),*> #borrow_mut_ident<#(#struct_rlt_args,)* #(#struct_lt_args,)* #(#struct_nonlt_args),*> #struct_where_clause {
321 fn unify_tys_hack(#(#local_idents: #borrow_mut_ty_hacks),*) -> #borrow_mut_ident<#(#struct_rlt_args,)* #(#struct_lt_args,)* #(#struct_nonlt_args),*> {
322 #borrow_mut_ident {
323 #(#field_idents: #local_idents,)*
324 }
325 }
326 }
327 ).to_tokens(tokens);
328
329 quote_spanned!(struct_span =>
330 unsafe impl<#(#borrow_lt_params,)* #(#struct_nonlt_params),*> __rental_prelude::#rental_trait_ident<#(#struct_rlt_args),*> for #item_ident #struct_impl_args #struct_where_clause {
331 type Borrow = #borrow_ident<#(#struct_rlt_args,)* #(#struct_lt_args,)* #(#struct_nonlt_args),*>;
332 type BorrowMut = #borrow_mut_ident<#(#struct_rlt_args,)* #(#struct_lt_args,)* #(#struct_nonlt_args),*>;
333 }
334 ).to_tokens(tokens);
335
336 quote_spanned!(struct_span =>
337 #[allow(dead_code, unused_mut, unused_unsafe, non_camel_case_types)]
338 impl #struct_impl_params #item_ident #struct_impl_args #struct_where_clause {
339 /// Create a new instance of the rental struct.
340 ///
341 /// The first argument provided is the head, followed by a series of closures, one for each tail field. Each of these closures will receive, as its arguments, a borrow of the previous field, followed by borrows of the remaining prefix fields if the struct is a shared rental. If the struct is a mutable rental, only the immediately preceding field is passed.
342 pub fn new<#(#tail_closure_tys),*>(
343 mut #head_ident: #head_ty,
344 #(#tail_idents: #tail_closure_tys),*
345 ) -> Self where #(#tail_closure_tys: #tail_closure_bounds),*
346 {
347 #(#static_assert_prefix_stable_derefs)*
348
349 #(let mut #tail_idents = unsafe { __rental_prelude::transmute::<_, #tail_tys>(#tail_closure_exprs) };)*
350
351 #item_ident {
352 #(#field_idents: #local_idents,)*
353 }
354 }
355
356 /// Attempt to create a new instance of the rental struct.
357 ///
358 /// As `new`, but each closure returns a `Result`. If one of them fails, execution is short-circuited and a tuple of the error and the original head value is returned to you.
359 pub fn try_new<#(#tail_closure_tys,)* __E>(
360 mut #head_ident: #head_ty,
361 #(#tail_idents: #tail_closure_tys),*
362 ) -> __rental_prelude::RentalResult<Self, __E, #head_ty> where
363 #(#tail_closure_tys: #tail_try_closure_bounds,)*
364 {
365 #(#static_assert_prefix_stable_derefs)*
366
367 #(let mut #tail_idents = {
368 let temp = #tail_try_closure_exprs.map(|t| unsafe { __rental_prelude::transmute::<_, #tail_tys>(t) });
369 match temp {
370 __rental_prelude::Result::Ok(t) => t,
371 __rental_prelude::Result::Err(e) => return __rental_prelude::Result::Err(__rental_prelude::RentalError(e.into(), #head_ident_rep)),
372 }
373 };)*
374
375 __rental_prelude::Result::Ok(#item_ident {
376 #(#field_idents: #local_idents,)*
377 })
378 }
379
380 /// Attempt to create a new instance of the rental struct.
381 ///
382 /// As `try_new`, but only the error value is returned upon failure; the head value is dropped. This method interacts more smoothly with existing error conversions.
383 pub fn try_new_or_drop<#(#tail_closure_tys,)* __E>(
384 mut #head_ident: #head_ty,
385 #(#tail_idents: #tail_closure_tys),*
386 ) -> __rental_prelude::Result<Self, __E> where
387 #(#tail_closure_tys: #tail_try_closure_bounds,)*
388 {
389 #(#static_assert_prefix_stable_derefs)*
390
391 #(let mut #tail_idents = {
392 let temp = #tail_try_closure_exprs.map(|t| unsafe { __rental_prelude::transmute::<_, #tail_tys>(t) });
393 match temp {
394 __rental_prelude::Result::Ok(t) => t,
395 __rental_prelude::Result::Err(e) => return __rental_prelude::Result::Err(e.into()),
396 }
397 };)*
398
399 __rental_prelude::Result::Ok(#item_ident {
400 #(#field_idents: #local_idents,)*
401 })
402 }
403
404 /// Return lifetime-erased shared borrows of the fields of the struct.
405 ///
406 /// This is unsafe because the erased lifetimes are fake. Use this only if absolutely necessary and be very mindful of what the true lifetimes are.
407 pub unsafe fn all_erased(#self_ref_param) -> <Self as __rental_prelude::#rental_trait_ident>::Borrow {
408 #borrow_ident::unify_tys_hack(#(__rental_prelude::transmute(#borrow_exprs),)*)
409 }
410
411 /// Return a lifetime-erased mutable borrow of the suffix of the struct.
412 ///
413 /// This is unsafe because the erased lifetimes are fake. Use this only if absolutely necessary and be very mindful of what the true lifetimes are.
414 pub unsafe fn all_mut_erased(#self_mut_param) -> <Self as __rental_prelude::#rental_trait_ident>::BorrowMut {
415 #borrow_mut_ident::unify_tys_hack(#(__rental_prelude::transmute(#borrow_mut_exprs),)*)
416 }
417
418 /// Execute a closure on the shared suffix of the struct.
419 ///
420 /// The closure may return any value not bounded by one of the special rental lifetimes of the struct.
421 pub fn rent<__F, __R>(#self_ref_param, f: __F) -> __R where
422 __F: for<#(#suffix_rlt_args,)*> __rental_prelude::FnOnce(#borrow_suffix_ty) -> __R,
423 __R: #(#struct_lt_args +)*,
424 {
425 f(#borrow_suffix_expr)
426 }
427
428 /// Execute a closure on the mutable suffix of the struct.
429 ///
430 /// The closure may return any value not bounded by one of the special rental lifetimes of the struct.
431 pub fn rent_mut<__F, __R>(#self_mut_param, f: __F) -> __R where
432 __F: for<#(#suffix_rlt_args,)*> __rental_prelude::FnOnce(#borrow_mut_suffix_ty) -> __R,
433 __R: #(#struct_lt_args +)*,
434 {
435 f(#borrow_mut_suffix_expr)
436 }
437
438 /// Return a shared reference from the shared suffix of the struct.
439 ///
440 /// This is a subtle variation of `rent` where it is legal to return a reference bounded by a rental lifetime, because that lifetime is reborrowed away before it is returned to you.
441 pub fn ref_rent<__F, __R>(#self_ref_param, f: __F) -> &__R where
442 __F: for<#(#suffix_rlt_args,)*> __rental_prelude::FnOnce(#borrow_suffix_ty) -> &#last_rlt_arg __R,
443 __R: ?Sized //#(#struct_lt_args +)*,
444 {
445 f(#borrow_suffix_expr)
446 }
447
448 /// Optionally return a shared reference from the shared suffix of the struct.
449 ///
450 /// This is a subtle variation of `rent` where it is legal to return a reference bounded by a rental lifetime, because that lifetime is reborrowed away before it is returned to you.
451 pub fn maybe_ref_rent<__F, __R>(#self_ref_param, f: __F) -> __rental_prelude::Option<&__R> where
452 __F: for<#(#suffix_rlt_args,)*> __rental_prelude::FnOnce(#borrow_suffix_ty) -> __rental_prelude::Option<&#last_rlt_arg __R>,
453 __R: ?Sized //#(#struct_lt_args +)*,
454 {
455 f(#borrow_suffix_expr)
456 }
457
458 /// Try to return a shared reference from the shared suffix of the struct, or an error on failure.
459 ///
460 /// This is a subtle variation of `rent` where it is legal to return a reference bounded by a rental lifetime, because that lifetime is reborrowed away before it is returned to you.
461 pub fn try_ref_rent<__F, __R, __E>(#self_ref_param, f: __F) -> __rental_prelude::Result<&__R, __E> where
462 __F: for<#(#suffix_rlt_args,)*> __rental_prelude::FnOnce(#borrow_suffix_ty) -> __rental_prelude::Result<&#last_rlt_arg __R, __E>,
463 __R: ?Sized //#(#struct_lt_args +)*,
464 {
465 f(#borrow_suffix_expr)
466 }
467
468 /// Return a mutable reference from the mutable suffix of the struct.
469 ///
470 /// This is a subtle variation of `rent_mut` where it is legal to return a reference bounded by a rental lifetime, because that lifetime is reborrowed away before it is returned to you.
471 pub fn ref_rent_mut<__F, __R>(#self_mut_param, f: __F) -> &mut __R where
472 __F: for<#(#suffix_rlt_args,)*> __rental_prelude::FnOnce(#borrow_mut_suffix_ty) -> &#last_rlt_arg mut __R,
473 __R: ?Sized //#(#struct_lt_args +)*,
474 {
475 f(#borrow_mut_suffix_expr)
476 }
477
478 /// Optionally return a mutable reference from the mutable suffix of the struct.
479 ///
480 /// This is a subtle variation of `rent_mut` where it is legal to return a reference bounded by a rental lifetime, because that lifetime is reborrowed away before it is returned to you.
481 pub fn maybe_ref_rent_mut<__F, __R>(#self_mut_param, f: __F) -> __rental_prelude::Option<&mut __R> where
482 __F: for<#(#suffix_rlt_args,)*> __rental_prelude::FnOnce(#borrow_mut_suffix_ty) -> __rental_prelude::Option<&#last_rlt_arg mut __R>,
483 __R: ?Sized //#(#struct_lt_args +)*,
484 {
485 f(#borrow_mut_suffix_expr)
486 }
487
488 /// Try to return a mutable reference from the mutable suffix of the struct, or an error on failure.
489 ///
490 /// This is a subtle variation of `rent_mut` where it is legal to return a reference bounded by a rental lifetime, because that lifetime is reborrowed away before it is returned to you.
491 pub fn try_ref_rent_mut<__F, __R, __E>(#self_mut_param, f: __F) -> __rental_prelude::Result<&mut __R, __E> where
492 __F: for<#(#suffix_rlt_args,)*> __rental_prelude::FnOnce(#borrow_mut_suffix_ty) -> __rental_prelude::Result<&#last_rlt_arg mut __R, __E>,
493 __R: ?Sized //#(#struct_lt_args +)*,
494 {
495 f(#borrow_mut_suffix_expr)
496 }
497
498 /// Drop the rental struct and return the original head value to you.
499 pub fn into_head(#self_move_param) -> #head_ty {
500 let Self{#head_ident, ..} = #self_arg;
501 #head_ident
502 }
503 }
504 ).to_tokens(tokens);
505
506 if !attribs.is_rental_mut {
507 quote_spanned!(struct_span =>
508 #[allow(dead_code)]
509 impl #struct_impl_params #item_ident #struct_impl_args #struct_where_clause {
510 /// Return a shared reference to the head field of the struct.
511 pub fn head(#self_ref_param) -> &<#head_ty as __rental_prelude::Deref>::Target {
512 &*#self_arg.#head_ident
513 }
514
515 /// Execute a closure on shared borrows of the fields of the struct.
516 ///
517 /// The closure may return any value not bounded by one of the special rental lifetimes of the struct.
518 pub fn rent_all<__F, __R>(#self_ref_param, f: __F) -> __R where
519 __F: for<#(#struct_rlt_args,)*> __rental_prelude::FnOnce(#borrow_ident<#(#struct_rlt_args,)* #(#struct_lt_args,)* #(#struct_nonlt_args),*>) -> __R,
520 __R: #(#struct_lt_args +)*,
521 {
522 f(unsafe { #item_ident::all_erased(#self_arg) })
523 }
524
525 /// Return a shared reference from shared borrows of the fields of the struct.
526 ///
527 /// This is a subtle variation of `rent_all` where it is legal to return a reference bounded by a rental lifetime, because that lifetime is reborrowed away before it is returned to you.
528 pub fn ref_rent_all<__F, __R>(#self_ref_param, f: __F) -> &__R where
529 __F: for<#(#struct_rlt_args,)*> __rental_prelude::FnOnce(#borrow_ident<#(#struct_rlt_args,)* #(#struct_lt_args,)* #(#struct_nonlt_args),*>) -> &#last_rlt_arg __R,
530 __R: ?Sized //#(#struct_lt_args +)*,
531 {
532 f(unsafe { #item_ident::all_erased(#self_arg) })
533 }
534
535 /// Optionally return a shared reference from shared borrows of the fields of the struct.
536 ///
537 /// This is a subtle variation of `rent_all` where it is legal to return a reference bounded by a rental lifetime, because that lifetime is reborrowed away before it is returned to you.
538 pub fn maybe_ref_rent_all<__F, __R>(#self_ref_param, f: __F) -> __rental_prelude::Option<&__R> where
539 __F: for<#(#struct_rlt_args,)*> __rental_prelude::FnOnce(#borrow_ident<#(#struct_rlt_args,)* #(#struct_lt_args,)* #(#struct_nonlt_args),*>) -> __rental_prelude::Option<&#last_rlt_arg __R>,
540 __R: ?Sized //#(#struct_lt_args +)*,
541 {
542 f(unsafe { #item_ident::all_erased(#self_arg) })
543 }
544
545 /// Try to return a shared reference from shared borrows of the fields of the struct, or an error on failure.
546 ///
547 /// This is a subtle variation of `rent_all` where it is legal to return a reference bounded by a rental lifetime, because that lifetime is reborrowed away before it is returned to you.
548 pub fn try_ref_rent_all<__F, __R, __E>(#self_ref_param, f: __F) -> __rental_prelude::Result<&__R, __E> where
549 __F: for<#(#struct_rlt_args,)*> __rental_prelude::FnOnce(#borrow_ident<#(#struct_rlt_args,)* #(#struct_lt_args,)* #(#struct_nonlt_args),*>) -> __rental_prelude::Result<&#last_rlt_arg __R, __E>,
550 __R: ?Sized //#(#struct_lt_args +)*,
551 {
552 f(unsafe { #item_ident::all_erased(#self_arg) })
553 }
554
555 /// Execute a closure on shared borrows of the prefix fields and a mutable borrow of the suffix field of the struct.
556 ///
557 /// The closure may return any value not bounded by one of the special rental lifetimes of the struct.
558 pub fn rent_all_mut<__F, __R>(#self_mut_param, f: __F) -> __R where
559 __F: for<#(#struct_rlt_args,)*> __rental_prelude::FnOnce(#borrow_mut_ident<#(#struct_rlt_args,)* #(#struct_lt_args,)* #(#struct_nonlt_args),*>) -> __R,
560 __R: #(#struct_lt_args +)*,
561 {
562 f(unsafe { #item_ident::all_mut_erased(#self_arg) })
563 }
564
565 /// Return a mutable reference from shared borrows of the prefix fields and a mutable borrow of the suffix field of the struct.
566 ///
567 /// This is a subtle variation of `rent_all_mut` where it is legal to return a reference bounded by a rental lifetime, because that lifetime is reborrowed away before it is returned to you.
568 pub fn ref_rent_all_mut<__F, __R>(#self_mut_param, f: __F) -> &mut __R where
569 __F: for<#(#struct_rlt_args,)*> __rental_prelude::FnOnce(#borrow_mut_ident<#(#struct_rlt_args,)* #(#struct_lt_args,)* #(#struct_nonlt_args),*>) -> &#last_rlt_arg mut __R,
570 __R: ?Sized //#(#struct_lt_args +)*,
571 {
572 f(unsafe { #item_ident::all_mut_erased(#self_arg) })
573 }
574
575 /// Optionally return a mutable reference from shared borrows of the prefix fields and a mutable borrow of the suffix field of the struct.
576 ///
577 /// This is a subtle variation of `rent_all_mut` where it is legal to return a reference bounded by a rental lifetime, because that lifetime is reborrowed away before it is returned to you.
578 pub fn maybe_ref_rent_all_mut<__F, __R>(#self_mut_param, f: __F) -> __rental_prelude::Option<&mut __R> where
579 __F: for<#(#struct_rlt_args,)*> __rental_prelude::FnOnce(#borrow_mut_ident<#(#struct_rlt_args,)* #(#struct_lt_args,)* #(#struct_nonlt_args),*>) -> __rental_prelude::Option<&#last_rlt_arg mut __R>,
580 __R: ?Sized //#(#struct_lt_args +)*,
581 {
582 f(unsafe { #item_ident::all_mut_erased(#self_arg) })
583 }
584
585 /// Try to return a mutable reference from shared borrows of the prefix fields and a mutable borrow of the suffix field of the struct, or an error on failure.
586 ///
587 /// This is a subtle variation of `rent_all_mut` where it is legal to return a reference bounded by a rental lifetime, because that lifetime is reborrowed away before it is returned to you.
588 pub fn try_ref_rent_all_mut<__F, __R, __E>(#self_mut_param, f: __F) -> __rental_prelude::Result<&mut __R, __E> where
589 __F: for<#(#struct_rlt_args,)*> __rental_prelude::FnOnce(#borrow_mut_ident<#(#struct_rlt_args,)* #(#struct_lt_args,)* #(#struct_nonlt_args),*>) -> __rental_prelude::Result<&#last_rlt_arg mut __R, __E>,
590 __R: ?Sized //#(#struct_lt_args +)*,
591 {
592 f(unsafe { #item_ident::all_mut_erased(#self_arg) })
593 }
594 }
595 ).to_tokens(tokens);
596 }
597
598 if attribs.is_debug {
599 if attribs.is_rental_mut {
600 quote_spanned!(struct_info.ident.span()/*.resolved_at(def_site)*/ =>
601 impl #struct_impl_params __rental_prelude::fmt::Debug for #item_ident #struct_impl_args #struct_where_clause #where_extra #suffix_ty: __rental_prelude::fmt::Debug {
602 fn fmt(&self, f: &mut __rental_prelude::fmt::Formatter) -> __rental_prelude::fmt::Result {
603 f.debug_struct(#item_ident_str)
604 .field(#suffix_ident_str, &self.#suffix_ident)
605 .finish()
606 }
607 }
608 ).to_tokens(tokens);
609 } else {
610 quote_spanned!(struct_info.ident.span()/*.resolved_at(def_site)*/ =>
611 impl #struct_impl_params __rental_prelude::fmt::Debug for #item_ident #struct_impl_args #struct_where_clause #where_extra #(#field_tys: __rental_prelude::fmt::Debug),* {
612 fn fmt(&self, f: &mut __rental_prelude::fmt::Formatter) -> __rental_prelude::fmt::Result {
613 f.debug_struct(#item_ident_str)
614 #(.field(#field_ident_strs, &self.#field_idents))*
615 .finish()
616 }
617 }
618 ).to_tokens(tokens);
619 }
620 }
621
622 if attribs.is_clone {
623 quote_spanned!(struct_info.ident.span()/*.resolved_at(def_site)*/ =>
624 impl #struct_impl_params __rental_prelude::Clone for #item_ident #struct_impl_args #struct_where_clause #where_extra #(#prefix_tys: #prefix_clone_traits,)* #suffix_ty: __rental_prelude::Clone {
625 fn clone(&self) -> Self {
626 #item_ident {
627 #(#local_idents: __rental_prelude::Clone::clone(&self.#field_idents),)*
628 }
629 }
630 }
631 ).to_tokens(tokens);
632 }
633
634 // if fields[fields.len() - 1].subrental.is_some() {
635 // quote_spanned!(struct_span =>
636 // impl<#(#borrow_lt_params,)* #(#struct_nonlt_params),*> __rental_prelude::IntoSuffix for #borrow_ident<#(#struct_rlt_args,)* #(#struct_lt_args,)* #(#struct_nonlt_args),*> #struct_where_clause {
637 // type Suffix = <#borrow_suffix_ty as __rental_prelude::IntoSuffix>::Suffix;
638 //
639 // #[allow(non_shorthand_field_patterns)]
640 // fn into_suffix(self) -> <Self as __rental_prelude::IntoSuffix>::Suffix {
641 // let #borrow_ident{#suffix_ident: suffix, ..};
642 // suffix.into_suffix()
643 // }
644 // }
645 // ).to_tokens(tokens);
646 //
647 // quote_spanned!(struct_span =>
648 // impl<#(#borrow_lt_params,)* #(#struct_nonlt_params),*> __rental_prelude::IntoSuffix for #borrow_mut_ident<#(#struct_rlt_args,)* #(#struct_lt_args,)* #(#struct_nonlt_args),*> #struct_where_clause {
649 // type Suffix = <#borrow_mut_suffix_ty as __rental_prelude::IntoSuffix>::Suffix;
650 //
651 // #[allow(non_shorthand_field_patterns)]
652 // fn into_suffix(self) -> <Self as __rental_prelude::IntoSuffix>::Suffix {
653 // let #borrow_mut_ident{#suffix_ident: suffix, ..};
654 // suffix.into_suffix()
655 // }
656 // }
657 // ).to_tokens(tokens);
658 //
659 // if attribs.is_deref_suffix {
660 // quote_spanned!(suffix_ty_span =>
661 // impl #struct_impl_params __rental_prelude::Deref for #item_ident #struct_impl_args #struct_where_clause {
662 // type Target = <#suffix_ty as __rental_prelude::Deref>::Target;
663 //
664 // fn deref(&self) -> &<Self as __rental_prelude::Deref>::Target {
665 // #item_ident::ref_rent(self, |suffix| &**__rental_prelude::IntoSuffix::into_suffix(suffix))
666 // }
667 // }
668 // ).to_tokens(tokens);
669 // }
670 //
671 // if attribs.is_deref_mut_suffix {
672 // quote_spanned!(suffix_ty_span =>
673 // impl #struct_impl_params __rental_prelude::DerefMut for #item_ident #struct_impl_args #struct_where_clause {
674 // fn deref_mut(&mut self) -> &mut <Self as __rental_prelude::Deref>::Target {
675 // #item_ident.ref_rent_mut(self, |suffix| &mut **__rental_prelude::IntoSuffix::into_suffix(suffix))
676 // }
677 // }
678 // ).to_tokens(tokens);
679 // }
680 // } else {
681 quote_spanned!(struct_span =>
682 impl<#(#borrow_lt_params,)* #(#struct_nonlt_params),*> __rental_prelude::IntoSuffix for #borrow_ident<#(#struct_rlt_args,)* #(#struct_lt_args,)* #(#struct_nonlt_args),*> #struct_where_clause {
683 type Suffix = #borrow_suffix_ty;
684
685 #[allow(non_shorthand_field_patterns)]
686 fn into_suffix(self) -> <Self as __rental_prelude::IntoSuffix>::Suffix {
687 let #borrow_ident{#suffix_ident: suffix, ..} = self;
688 suffix
689 }
690 }
691 ).to_tokens(tokens);
692
693 quote_spanned!(struct_span =>
694 impl<#(#borrow_lt_params,)* #(#struct_nonlt_params),*> __rental_prelude::IntoSuffix for #borrow_mut_ident<#(#struct_rlt_args,)* #(#struct_lt_args,)* #(#struct_nonlt_args),*> #struct_where_clause {
695 type Suffix = #borrow_mut_suffix_ty;
696
697 #[allow(non_shorthand_field_patterns)]
698 fn into_suffix(self) -> <Self as __rental_prelude::IntoSuffix>::Suffix {
699 let #borrow_mut_ident{#suffix_ident: suffix, ..} = self;
700 suffix
701 }
702 }
703 ).to_tokens(tokens);
704
705 if attribs.is_deref_suffix {
706 quote_spanned!(suffix_ty_span =>
707 impl #struct_impl_params __rental_prelude::Deref for #item_ident #struct_impl_args #struct_where_clause #where_extra {
708 type Target = <#suffix_ty as __rental_prelude::Deref>::Target;
709
710 fn deref(&self) -> &<Self as __rental_prelude::Deref>::Target {
711 #item_ident::ref_rent(self, |suffix| &**suffix)
712 }
713 }
714 ).to_tokens(tokens);
715 }
716
717 if attribs.is_deref_mut_suffix {
718 quote_spanned!(suffix_ty_span =>
719 impl #struct_impl_params __rental_prelude::DerefMut for #item_ident #struct_impl_args #struct_where_clause {
720 fn deref_mut(&mut self) -> &mut <Self as __rental_prelude::Deref>::Target {
721 #item_ident::ref_rent_mut(self, |suffix| &mut **suffix)
722 }
723 }
724 ).to_tokens(tokens);
725 }
726 // }
727
728 if attribs.is_deref_suffix {
729 quote_spanned!(suffix_ty_span =>
730 impl #struct_impl_params __rental_prelude::AsRef<<Self as __rental_prelude::Deref>::Target> for #item_ident #struct_impl_args #struct_where_clause {
731 fn as_ref(&self) -> &<Self as __rental_prelude::Deref>::Target {
732 &**self
733 }
734 }
735 ).to_tokens(tokens);
736 }
737
738 if attribs.is_deref_mut_suffix {
739 quote_spanned!(suffix_ty_span =>
740 impl #struct_impl_params __rental_prelude::AsMut<<Self as __rental_prelude::Deref>::Target> for #item_ident #struct_impl_args #struct_where_clause {
741 fn as_mut(&mut self) -> &mut <Self as __rental_prelude::Deref>::Target {
742 &mut **self
743 }
744 }
745 ).to_tokens(tokens);
746 }
747
748 if attribs.is_covariant {
749 quote_spanned!(struct_info.ident.span()/*.resolved_at(def_site)*/ =>
750 #[allow(dead_code)]
751 impl #struct_impl_params #item_ident #struct_impl_args #struct_where_clause {
752 /// Borrow all fields of the struct by reborrowing away the rental lifetimes.
753 ///
754 /// This is safe because the lifetimes are verified to be covariant first.
755 pub fn all<'__s>(#self_lt_ref_param) -> <Self as __rental_prelude::#rental_trait_ident>::Borrow {
756 unsafe {
757 let _covariant = __rental_prelude::PhantomData::<#borrow_ident<#(#static_rlt_args,)* #(#struct_lt_args,)* #(#struct_nonlt_args),*>>;
758 let _covariant: __rental_prelude::PhantomData<#borrow_ident<#(#self_rlt_args,)* #(#struct_lt_args,)* #(#struct_nonlt_args),*>> = _covariant;
759
760 #item_ident::all_erased(#self_arg)
761 }
762 }
763
764 /// Borrow the suffix field of the struct by reborrowing away the rental lifetimes.
765 ///
766 /// This is safe because the lifetimes are verified to be covariant first.
767 pub fn suffix(#self_ref_param) -> <<Self as __rental_prelude::#rental_trait_ident>::Borrow as __rental_prelude::IntoSuffix>::Suffix {
768 &#self_arg.#suffix_ident
769 }
770 }
771 ).to_tokens(tokens);
772 }
773
774 if let Some(ref map_suffix_param) = attribs.map_suffix_param {
775 let mut replacer = MapTyParamReplacer{
776 ty_param: map_suffix_param,
777 };
778
779 let mapped_suffix_param = replacer.fold_type_param(map_suffix_param.clone());
780 let mapped_ty = replacer.fold_path(parse_quote!(#item_ident #struct_impl_args));
781 let mapped_suffix_ty = replacer.fold_type(suffix_orig_ty.clone());
782
783 let mut map_where_clause = syn::WhereClause{
784 where_token: Default::default(),
785 predicates: syn::punctuated::Punctuated::from_iter(
786 struct_generics.type_params().filter(|p| p.ident != map_suffix_param.ident).filter_map(|p| {
787 let mut mapped_param = p.clone();
788 mapped_param.bounds = syn::punctuated::Punctuated::new();
789
790 for mapped_bound in p.bounds.iter().filter(|b| {
791 let mut finder = MapTyParamFinder {
792 ty_param: map_suffix_param,
793 found: false,
794 };
795 finder.visit_type_param_bound(b);
796 finder.found
797 }).map(|b| {
798 let mut replacer = MapTyParamReplacer{
799 ty_param: map_suffix_param,
800 };
801
802 replacer.fold_type_param_bound(b.clone())
803 }) {
804 mapped_param.bounds.push(mapped_bound)
805 }
806
807 if mapped_param.bounds.len() > 0 {
808 Some(syn::punctuated::Pair::Punctuated(parse_quote!(#mapped_param), Default::default()))
809 } else {
810 None
811 }
812 }).chain(
813 struct_where_clause.iter().flat_map(|w| w.predicates.iter()).filter(|p| {
814 let mut finder = MapTyParamFinder {
815 ty_param: map_suffix_param,
816 found: false,
817 };
818 finder.visit_where_predicate(p);
819 finder.found
820 }).map(|p| {
821 let mut replacer = MapTyParamReplacer{
822 ty_param: map_suffix_param,
823 };
824
825 syn::punctuated::Pair::Punctuated(replacer.fold_where_predicate(p.clone()), Default::default())
826 })
827 )
828 )
829 };
830
831 let mut try_map_where_clause = map_where_clause.clone();
832 map_where_clause.predicates.push(parse_quote!(
833 __F: for<#(#suffix_rlt_args),*> __rental_prelude::FnOnce(#suffix_orig_ty) -> #mapped_suffix_ty
834 ));
835 try_map_where_clause.predicates.push(parse_quote!(
836 __F: for<#(#suffix_rlt_args),*> __rental_prelude::FnOnce(#suffix_orig_ty) -> __rental_prelude::Result<#mapped_suffix_ty, __E>
837 ));
838
839 quote_spanned!(struct_span =>
840 #[allow(dead_code)]
841 impl #struct_impl_params #item_ident #struct_impl_args #struct_where_clause {
842 /// Maps the suffix field of the rental struct to a different type.
843 ///
844 /// Consumes the rental struct and applies the closure to the suffix field. A new rental struct is then constructed with the original prefix and new suffix.
845 pub fn map<#mapped_suffix_param, __F>(#self_move_param, __f: __F) -> #mapped_ty #map_where_clause {
846 let #item_ident{ #(#field_idents,)* } = #self_arg;
847
848 let #suffix_ident = __f(#suffix_ident);
849
850 #item_ident{ #(#field_idents: #local_idents,)* }
851 }
852
853 /// Try to map the suffix field of the rental struct to a different type.
854 ///
855 /// As `map`, but the closure may fail. Upon failure, the tail is dropped, and the error is returned to you along with the head.
856 pub fn try_map<#mapped_suffix_param, __F, __E>(#self_move_param, __f: __F) -> __rental_prelude::RentalResult<#mapped_ty, __E, #head_ty> #try_map_where_clause {
857 let #item_ident{ #(#field_idents,)* } = #self_arg;
858
859 match __f(#suffix_ident) {
860 __rental_prelude::Result::Ok(#suffix_ident) => __rental_prelude::Result::Ok(#item_ident { #(#field_idents: #local_idents,)* }),
861 __rental_prelude::Result::Err(__e) => __rental_prelude::Result::Err(__rental_prelude::RentalError(__e, #head_ident)),
862 }
863 }
864
865 /// Try to map the suffix field of the rental struct to a different type.
866 ///
867 /// As `map`, but the closure may fail. Upon failure, the struct is dropped and the error is returned.
868 pub fn try_map_or_drop<#mapped_suffix_param, __F, __E>(#self_move_param, __f: __F) -> __rental_prelude::Result<#mapped_ty, __E> #try_map_where_clause {
869 let #item_ident{ #(#field_idents,)* } = #self_arg;
870
871 let #suffix_ident = __f(#suffix_ident)?;
872
873 Ok(#item_ident{ #(#field_idents: #local_idents,)* })
874 }
875 }
876 ).to_tokens(tokens);
877 }
878 }
879
880
get_struct_attribs(struct_info: &syn::ItemStruct) -> RentalStructAttribs881 fn get_struct_attribs(struct_info: &syn::ItemStruct) -> RentalStructAttribs
882 {
883 let mut rattribs = struct_info.attrs.clone();
884
885 let mut is_rental_mut = false;
886 let mut is_debug = false;
887 let mut is_clone = false;
888 let mut is_deref_suffix = false;
889 let mut is_deref_mut_suffix = false;
890 let mut is_covariant = false;
891 let mut map_suffix_param = None;
892
893 if let Some(rental_pos) = rattribs.iter()/*.filter(|attr| !attr.is_sugared_doc)*/.position(|attr| match attr.parse_meta().expect(&format!("Struct `{}` Attribute `{}` is not properly formatted.", struct_info.ident, attr.path.clone().into_token_stream())) {
894 syn::Meta::Path(ref attr_ident) => {
895 is_rental_mut = match attr_ident.segments.first().map(|s| s.ident.to_string()).as_ref().map(String::as_str) {
896 Some("rental") => false,
897 Some("rental_mut") => true,
898 _ => return false,
899 };
900
901 true
902 },
903 syn::Meta::List(ref list) => {
904 is_rental_mut = match list.path.segments.first().map(|s| s.ident.to_string()).as_ref().map(String::as_str) {
905 Some("rental") => false,
906 Some("rental_mut") => true,
907 _ => return false,
908 };
909
910 let leftover = list.nested.iter().filter(|nested| {
911 if let syn::NestedMeta::Meta(ref meta) = **nested {
912 match *meta {
913 syn::Meta::Path(ref ident) => {
914 match ident.segments.first().map(|s| s.ident.to_string()).as_ref().map(String::as_str) {
915 Some("debug") => {
916 is_debug = true;
917 false
918 },
919 Some("clone") => {
920 is_clone = true;
921 false
922 },
923 Some("deref_suffix") => {
924 is_deref_suffix = true;
925 false
926 },
927 Some("deref_mut_suffix") => {
928 is_deref_suffix = true;
929 is_deref_mut_suffix = true;
930 false
931 },
932 Some("covariant") => {
933 is_covariant = true;
934 false
935 },
936 Some("map_suffix") => {
937 panic!("Struct `{}` `map_suffix` flag expects ` = \"T\"`.", struct_info.ident);
938 },
939 _ => true,
940 }
941 },
942 syn::Meta::NameValue(ref name_value) => {
943 match name_value.path.segments.first().map(|s| s.ident.to_string()).as_ref().map(String::as_str) {
944 Some("map_suffix") => {
945 if let syn::Lit::Str(ref ty_param_str) = name_value.lit {
946 let ty_param_str = ty_param_str.value();
947 let ty_param = struct_info.generics.type_params().find(|ty_param| {
948 if ty_param.ident.to_string() == ty_param_str {
949 return true;
950 }
951
952 false
953 }).unwrap_or_else(|| {
954 panic!("Struct `{}` `map_suffix` param `{}` does not name a type parameter.", struct_info.ident, ty_param_str);
955 });
956
957 let mut finder = MapTyParamFinder{
958 ty_param: &ty_param,
959 found: false,
960 };
961
962 if struct_info.fields.iter().take(struct_info.fields.iter().count() - 1).any(|f| {
963 finder.found = false;
964 finder.visit_field(f);
965 finder.found
966 }) {
967 panic!("Struct `{}` `map_suffix` type param `{}` appears in a prefix field.", struct_info.ident, ty_param_str);
968 }
969
970 finder.found = false;
971 finder.visit_field(struct_info.fields.iter().last().unwrap());
972 if !finder.found {
973 panic!("Struct `{}` `map_suffix` type param `{}` does not appear in the suffix field.", struct_info.ident, ty_param_str);
974 }
975
976 map_suffix_param = Some(ty_param.clone());
977 false
978 } else {
979 panic!("Struct `{}` `map_suffix` flag expects ` = \"T\"`.", struct_info.ident);
980 }
981 },
982 _ => true,
983 }
984 },
985 _ => true,
986 }
987 } else {
988 true
989 }
990 }).count();
991
992 if leftover > 0 {
993 panic!("Struct `{}` rental attribute takes optional arguments: `debug`, `clone`, `deref_suffix`, `deref_mut_suffix`, `covariant`, and `map_suffix = \"T\"`.", struct_info.ident);
994 }
995
996 true
997 },
998 _ => false,
999 }) {
1000 rattribs.remove(rental_pos);
1001 } else {
1002 panic!("Struct `{}` must have a `rental` or `rental_mut` attribute.", struct_info.ident);
1003 }
1004
1005 if rattribs.iter().any(|attr| attr.path != syn::parse_str::<syn::Path>("doc").unwrap()) {
1006 panic!("Struct `{}` must not have attributes other than one `rental` or `rental_mut`.", struct_info.ident);
1007 }
1008
1009 if is_rental_mut && is_clone {
1010 panic!("Struct `{}` cannot be both `rental_mut` and `clone`.", struct_info.ident);
1011 }
1012
1013 RentalStructAttribs{
1014 doc: rattribs,
1015 is_rental_mut: is_rental_mut,
1016 is_debug: is_debug,
1017 is_clone: is_clone,
1018 is_deref_suffix: is_deref_suffix,
1019 is_deref_mut_suffix: is_deref_mut_suffix,
1020 is_covariant: is_covariant,
1021 map_suffix_param: map_suffix_param,
1022 }
1023 }
1024
1025
prepare_fields(struct_info: &syn::ItemStruct) -> (Vec<RentalField>, syn::token::Brace)1026 fn prepare_fields(struct_info: &syn::ItemStruct) -> (Vec<RentalField>, syn::token::Brace) {
1027 let def_site: Span = Span::call_site(); // FIXME: hygiene
1028 let call_site: Span = Span::call_site();
1029
1030 let (fields, fields_brace) = match struct_info.fields {
1031 syn::Fields::Named(ref fields) => (&fields.named, fields.brace_token),
1032 syn::Fields::Unnamed(..) => panic!("Struct `{}` must not be a tuple struct.", struct_info.ident),
1033 _ => panic!("Struct `{}` must have at least 2 fields.", struct_info.ident),
1034 };
1035
1036 if fields.len() < 2 {
1037 panic!("Struct `{}` must have at least 2 fields.", struct_info.ident);
1038 }
1039
1040 let mut rfields = Vec::with_capacity(fields.len());
1041 for (field_idx, field) in fields.iter().enumerate() {
1042 if field.vis != syn::Visibility::Inherited {
1043 panic!(
1044 "Struct `{}` field `{}` must be private.",
1045 struct_info.ident,
1046 field.ident.as_ref().map(|ident| ident.to_string()).unwrap_or_else(|| field_idx.to_string())
1047 );
1048 }
1049
1050 let mut rfattribs = field.attrs.clone();
1051 let mut subrental = None;
1052 let mut target_ty_hack = None;
1053
1054 if let Some(sr_pos) = rfattribs.iter().position(|attr| match attr.parse_meta() {
1055 Ok(syn::Meta::List(ref list)) if list.path.segments.first().map(|s| s.ident.to_string()).as_ref().map(String::as_str) == Some("subrental") => {
1056 panic!(
1057 "`subrental` attribute on struct `{}` field `{}` expects ` = arity`.",
1058 struct_info.ident,
1059 field.ident.as_ref().map(|ident| ident.to_string()).unwrap_or_else(|| field_idx.to_string())
1060 );
1061 },
1062 Ok(syn::Meta::Path(ref word)) if word.segments.first().map(|s| s.ident.to_string()).as_ref().map(String::as_str) == Some("subrental") => {
1063 panic!(
1064 "`subrental` attribute on struct `{}` field `{}` expects ` = arity`.",
1065 struct_info.ident,
1066 field.ident.as_ref().map(|ident| ident.to_string()).unwrap_or_else(|| field_idx.to_string())
1067 );
1068 },
1069 Ok(syn::Meta::NameValue(ref name_value)) if name_value.path.segments.first().map(|s| s.ident.to_string()).as_ref().map(String::as_str) == Some("subrental") => {
1070 match name_value.lit {
1071 syn::Lit::Int(ref arity) => {
1072 subrental = Some(Subrental{
1073 arity: arity.base10_parse::<usize>().unwrap(),
1074 rental_trait_ident: syn::Ident::new(&format!("Rental{}", arity.base10_parse::<usize>().unwrap()), def_site),
1075 })
1076 },
1077 _ => panic!(
1078 "`subrental` attribute on struct `{}` field `{}` expects ` = arity`.",
1079 struct_info.ident,
1080 field.ident.as_ref().map(|ident| ident.to_string()).unwrap_or_else(|| field_idx.to_string())
1081 ),
1082 }
1083
1084 true
1085 },
1086 _ => false,
1087 }) {
1088 rfattribs.remove(sr_pos);
1089 }
1090
1091 if subrental.is_some() && field_idx == fields.len() - 1 {
1092 panic!(
1093 "struct `{}` field `{}` cannot be a subrental because it is the suffix field.",
1094 struct_info.ident,
1095 field.ident.as_ref().map(|ident| ident.to_string()).unwrap_or_else(|| field_idx.to_string())
1096 );
1097 }
1098
1099 if let Some(tth_pos) = rfattribs.iter().position(|a|
1100 match a.parse_meta() {
1101 Ok(syn::Meta::NameValue(syn::MetaNameValue{ref path, lit: syn::Lit::Str(ref ty_str), ..})) if path.segments.first().map(|s| s.ident.to_string()).as_ref().map(String::as_str) == Some("target_ty") => {
1102 if let Ok(ty) = syn::parse_str::<syn::Type>(&ty_str.value()) {
1103 target_ty_hack = Some(ty);
1104
1105 true
1106 } else {
1107 panic!(
1108 "`target_ty` attribute on struct `{}` field `{}` has an invalid ty string.",
1109 struct_info.ident,
1110 field.ident.as_ref().map(|ident| ident.to_string()).unwrap_or_else(|| field_idx.to_string())
1111 );
1112 }
1113 },
1114 _ => false,
1115 }
1116 ) {
1117 rfattribs.remove(tth_pos);
1118 }
1119
1120 if field_idx == fields.len() - 1 && target_ty_hack.is_some() {
1121 panic!(
1122 "Struct `{}` field `{}` cannot have `target_ty` attribute because it is the suffix field.",
1123 struct_info.ident,
1124 field.ident.as_ref().map(|ident| ident.to_string()).unwrap_or_else(|| field_idx.to_string())
1125 );
1126 }
1127
1128 let target_ty_hack = target_ty_hack.as_ref().map(|ty| (*ty).clone()).or_else(|| if field_idx < fields.len() - 1 {
1129 let guess = if let syn::Type::Path(ref ty_path) = field.ty {
1130 match ty_path.path.segments[ty_path.path.segments.len() - 1] {
1131 syn::PathSegment{ref ident, arguments: syn::PathArguments::AngleBracketed(syn::AngleBracketedGenericArguments{ref args, ..})} => {
1132 if let Some(&syn::GenericArgument::Type(ref ty)) = args.first() {
1133 if ident == "Vec" {
1134 Some(syn::Type::Slice(syn::TypeSlice{bracket_token: Default::default(), elem: Box::new(ty.clone())}))
1135 } else {
1136 Some(ty.clone())
1137 }
1138 } else {
1139 None
1140 }
1141 },
1142 syn::PathSegment{ref ident, arguments: syn::PathArguments::None} => {
1143 if ident == "String" {
1144 Some(parse_quote!(str))
1145 } else {
1146 None
1147 }
1148 },
1149 _ => {
1150 None
1151 },
1152 }
1153 } else if let syn::Type::Reference(syn::TypeReference{elem: ref box_ty, ..}) = field.ty {
1154 Some((**box_ty).clone())
1155 } else {
1156 None
1157 };
1158
1159 let guess = guess.or_else(|| if field_idx == 0 {
1160 let field_ty = &field.ty;
1161 Some(parse_quote!(<#field_ty as __rental_prelude::Deref>::Target))
1162 } else {
1163 None
1164 });
1165
1166 if guess.is_none() {
1167 panic!("Struct `{}` field `{}` must be a type path with 1 type param, `String`, or a reference.", struct_info.ident, field.ident.as_ref().unwrap())
1168 }
1169
1170 guess
1171 } else {
1172 None
1173 });
1174
1175 if subrental.is_some() {
1176 if match target_ty_hack {
1177 Some(syn::Type::Path(ref ty_path)) => ty_path.qself.is_some(),
1178 Some(_) => true,
1179 _ => false,
1180 } {
1181 panic!(
1182 "Struct `{}` field `{}` must have an unqualified path for its `target_ty` to be a valid subrental.",
1183 struct_info.ident,
1184 field.ident.as_ref().map(|ident| ident.to_string()).unwrap_or_else(|| field_idx.to_string())
1185 );
1186 }
1187 }
1188
1189 let target_ty_hack_erased = target_ty_hack.as_ref().map(|tth| {
1190 let mut eraser = RentalLifetimeEraser{
1191 fields: &rfields,
1192 used_rlt_args: &mut Vec::new(),
1193 };
1194
1195 eraser.fold_type(tth.clone())
1196 });
1197
1198 let mut self_rlt_args = Vec::new();
1199 if let Some(Subrental{arity: sr_arity, ..}) = subrental {
1200 let field_ident = field.ident.as_ref().unwrap();
1201 for sr_idx in 0 .. sr_arity {
1202 self_rlt_args.push(syn::Lifetime::new(&format!("'{}_{}", field_ident, sr_idx), call_site));
1203 }
1204 } else {
1205 let field_ident = field.ident.as_ref().unwrap();
1206 self_rlt_args.push(syn::Lifetime::new(&format!("'{}", field_ident), call_site));
1207 }
1208
1209 let mut used_rlt_args = Vec::new();
1210 let rty = {
1211 let mut eraser = RentalLifetimeEraser{
1212 fields: &rfields,
1213 used_rlt_args: &mut used_rlt_args,
1214 };
1215
1216 eraser.fold_type(field.ty.clone())
1217 };
1218
1219 if rfattribs.iter().any(|attr| match attr.parse_meta() { Ok(syn::Meta::NameValue(syn::MetaNameValue{ref path, ..})) if path.segments.first().map(|s| s.ident.to_string()).as_ref().map(String::as_str) == Some("doc") => false, _ => true }) {
1220 panic!(
1221 "Struct `{}` field `{}` must not have attributes other than one `subrental` and `target_ty`.",
1222 struct_info.ident,
1223 field.ident.as_ref().map(|ident| ident.to_string()).unwrap_or_else(|| field_idx.to_string())
1224 );
1225 }
1226
1227 rfields.push(RentalField{
1228 name: field.ident.as_ref().unwrap().clone(),
1229 orig_ty: field.ty.clone(),
1230 erased: syn::Field{
1231 colon_token: field.colon_token,
1232 ident: field.ident.clone(),
1233 vis: field.vis.clone(),
1234 attrs: rfattribs,
1235 ty: rty,
1236 },
1237 subrental: subrental,
1238 self_rlt_args: self_rlt_args,
1239 used_rlt_args: used_rlt_args,
1240 target_ty_hack: target_ty_hack,
1241 target_ty_hack_erased: target_ty_hack_erased,
1242 });
1243 }
1244
1245 (rfields, fields_brace)
1246 }
1247
1248
make_borrow_quotes(self_arg: &proc_macro2::TokenStream, fields: &[RentalField], is_rental_mut: bool) -> Vec<BorrowQuotes>1249 fn make_borrow_quotes(self_arg: &proc_macro2::TokenStream, fields: &[RentalField], is_rental_mut: bool) -> Vec<BorrowQuotes> {
1250 let call_site: Span = Span::call_site();
1251
1252 (0 .. fields.len()).map(|idx| {
1253 let (field_ty, deref) = if idx == fields.len() - 1 {
1254 let orig_ty = &fields[idx].orig_ty;
1255 (
1256 quote!(#orig_ty),
1257 quote!()
1258 )
1259 } else {
1260 let orig_ty = &fields[idx].orig_ty;
1261 (
1262 quote!(<#orig_ty as __rental_prelude::Deref>::Target),
1263 quote!(*)
1264 )
1265 };
1266
1267 let field_ty_hack = fields[idx].target_ty_hack.as_ref().unwrap_or(&fields[idx].orig_ty);
1268 let field_ty_hack_erased = fields[idx].target_ty_hack_erased.as_ref().unwrap_or(&fields[idx].erased.ty);
1269
1270 if let Some(ref subrental) = fields[idx].subrental {
1271 let field_ident = &fields[idx].name;
1272 let rental_trait_ident = &subrental.rental_trait_ident;
1273 let field_rlt_args = &fields[idx].self_rlt_args;
1274
1275 let (ref borrow_ty_hack, ref borrow_mut_ty_hack, ref field_args) = if let syn::Type::Path(syn::TypePath{ref qself, path: ref ty_path}) = *field_ty_hack {
1276 let seg_idx = ty_path.segments.len() - 1;
1277 let ty_name = &ty_path.segments[seg_idx].ident.to_string();
1278
1279 let mut borrow_ty_path = ty_path.clone();
1280 borrow_ty_path.segments[seg_idx].ident = syn::Ident::new(&format!("{}_Borrow", ty_name), call_site);
1281 borrow_ty_path.segments[seg_idx].arguments = syn::PathArguments::None;
1282
1283 let mut borrow_mut_ty_path = ty_path.clone();
1284 borrow_mut_ty_path.segments[seg_idx].ident = syn::Ident::new(&format!("{}_BorrowMut", ty_name), call_site);
1285 borrow_mut_ty_path.segments[seg_idx].arguments = syn::PathArguments::None;
1286
1287 match ty_path.segments[seg_idx].arguments {
1288 syn::PathArguments::AngleBracketed(ref args) => {
1289 (
1290 syn::Type::Path(syn::TypePath{qself: qself.clone(), path: borrow_ty_path}),
1291 syn::Type::Path(syn::TypePath{qself: qself.clone(), path: borrow_mut_ty_path}),
1292 args.args.iter().collect::<Vec<_>>(),
1293 )
1294 },
1295 syn::PathArguments::None => {
1296 (
1297 syn::Type::Path(syn::TypePath{qself: qself.clone(), path: borrow_ty_path}),
1298 syn::Type::Path(syn::TypePath{qself: qself.clone(), path: borrow_mut_ty_path}),
1299 Vec::with_capacity(0),
1300 )
1301 },
1302 _ => panic!("Field `{}` must have angle-bracketed args.", fields[idx].name),
1303 }
1304 } else {
1305 panic!("Field `{}` must be a type path.", fields[idx].name)
1306 };
1307
1308 BorrowQuotes {
1309 ty: if idx == fields.len() - 1 || !is_rental_mut {
1310 quote!(<#field_ty as __rental_prelude::#rental_trait_ident<#(#field_rlt_args),*>>::Borrow)
1311 } else {
1312 quote!(__rental_prelude::PhantomData<<#field_ty as __rental_prelude::#rental_trait_ident<#(#field_rlt_args),*>>::Borrow>)
1313 },
1314 ty_hack: if idx == fields.len() - 1 || !is_rental_mut {
1315 quote!(#borrow_ty_hack<#(#field_rlt_args,)* #(#field_args),*>)
1316 } else {
1317 quote!(__rental_prelude::PhantomData<#borrow_ty_hack<#(#field_rlt_args,)* #(#field_args),*>>)
1318 },
1319 expr: if idx == fields.len() - 1 || !is_rental_mut {
1320 quote!(unsafe { <#field_ty_hack_erased>::all_erased(&#deref #self_arg.#field_ident) })
1321 } else {
1322 quote!(__rental_prelude::PhantomData::<()>)
1323 },
1324
1325 mut_ty: if idx == fields.len() - 1 {
1326 quote!(<#field_ty as __rental_prelude::#rental_trait_ident<#(#field_rlt_args),*>>::BorrowMut)
1327 } else if !is_rental_mut {
1328 quote!(<#field_ty as __rental_prelude::#rental_trait_ident<#(#field_rlt_args),*>>::Borrow)
1329 } else {
1330 quote!(__rental_prelude::PhantomData<<#field_ty as __rental_prelude::#rental_trait_ident<#(#field_rlt_args),*>>::BorrowMut>)
1331 },
1332 mut_ty_hack: if idx == fields.len() - 1 {
1333 quote!(#borrow_mut_ty_hack<#(#field_rlt_args,)* #(#field_args),*>)
1334 } else if !is_rental_mut {
1335 quote!(#borrow_ty_hack<#(#field_rlt_args,)* #(#field_args),*>)
1336 } else {
1337 quote!(__rental_prelude::PhantomData<#borrow_mut_ty_hack<#(#field_rlt_args,)* #(#field_args),*>>)
1338 },
1339 mut_expr: if idx == fields.len() - 1 {
1340 quote!(unsafe { <#field_ty_hack_erased>::all_mut_erased(&mut #deref #self_arg.#field_ident) })
1341 } else if !is_rental_mut {
1342 quote!(unsafe { <#field_ty_hack_erased>::all_erased(&#deref #self_arg.#field_ident) })
1343 } else {
1344 quote!(__rental_prelude::PhantomData::<()>)
1345 },
1346
1347 new_ty: if !is_rental_mut {
1348 //quote!(<#field_ty as __rental_prelude::#rental_trait_ident<#(#field_rlt_args),*>>::Borrow)
1349 quote!(#borrow_ty_hack<#(#field_rlt_args,)* #(#field_args),*>)
1350 } else {
1351 //quote!(<#field_ty as __rental_prelude::#rental_trait_ident<#(#field_rlt_args),*>>::BorrowMut)
1352 quote!(#borrow_mut_ty_hack<#(#field_rlt_args,)* #(#field_args),*>)
1353 },
1354 new_expr: if !is_rental_mut {
1355 quote!(unsafe { <#field_ty_hack_erased>::all_erased(&#deref #field_ident) })
1356 } else {
1357 quote!(unsafe { <#field_ty_hack_erased>::all_mut_erased(&mut #deref #field_ident) })
1358 },
1359 }
1360 } else {
1361 let field_ident = &fields[idx].name;
1362 let field_rlt_arg = &fields[idx].self_rlt_args[0];
1363
1364 BorrowQuotes {
1365 ty: if idx == fields.len() - 1 || !is_rental_mut {
1366 quote!(&#field_rlt_arg (#field_ty))
1367 } else {
1368 quote!(__rental_prelude::PhantomData<&#field_rlt_arg #field_ty>)
1369 },
1370 ty_hack: if idx == fields.len() - 1 || !is_rental_mut {
1371 quote!(&#field_rlt_arg (#field_ty_hack))
1372 } else {
1373 quote!(__rental_prelude::PhantomData<&#field_rlt_arg #field_ty_hack>)
1374 },
1375 expr: if idx == fields.len() - 1 || !is_rental_mut {
1376 quote!(&#deref #self_arg.#field_ident)
1377 } else {
1378 quote!(__rental_prelude::PhantomData::<()>)
1379 },
1380
1381 mut_ty: if idx == fields.len() - 1 {
1382 quote!(&#field_rlt_arg mut (#field_ty))
1383 } else if !is_rental_mut {
1384 quote!(&#field_rlt_arg (#field_ty))
1385 } else {
1386 quote!(__rental_prelude::PhantomData<&#field_rlt_arg mut #field_ty>)
1387 },
1388 mut_ty_hack: if idx == fields.len() - 1 {
1389 quote!(&#field_rlt_arg mut (#field_ty_hack))
1390 } else if !is_rental_mut {
1391 quote!(&#field_rlt_arg (#field_ty_hack))
1392 } else {
1393 quote!(__rental_prelude::PhantomData<&#field_rlt_arg mut #field_ty_hack>)
1394 },
1395 mut_expr: if idx == fields.len() - 1 {
1396 quote!(&mut #deref #self_arg.#field_ident)
1397 } else if !is_rental_mut {
1398 quote!(&#deref #self_arg.#field_ident)
1399 } else {
1400 quote!(__rental_prelude::PhantomData::<()>)
1401 },
1402
1403 new_ty: if !is_rental_mut {
1404 //quote!(&#field_rlt_arg #field_ty)
1405 quote!(&#field_rlt_arg (#field_ty_hack))
1406 } else {
1407 //quote!(&#field_rlt_arg mut #field_ty)
1408 quote!(&#field_rlt_arg mut (#field_ty_hack))
1409 },
1410 new_expr: if !is_rental_mut {
1411 quote!(& #deref #field_ident)
1412 } else {
1413 quote!(&mut #deref #field_ident)
1414 },
1415 }
1416 }
1417 }).collect()
1418 }
1419
1420
make_tail_closure_quotes(fields: &[RentalField], borrows: &[BorrowQuotes], is_rental_mut: bool) -> Vec<ClosureQuotes>1421 fn make_tail_closure_quotes(fields: &[RentalField], borrows: &[BorrowQuotes], is_rental_mut: bool) -> Vec<ClosureQuotes> {
1422 (1 .. fields.len()).map(|idx| {
1423 let local_name = &fields[idx].name;
1424 let field_ty = &fields[idx].orig_ty;
1425
1426 if !is_rental_mut {
1427 let prev_new_tys_reverse = &borrows[0 .. idx].iter().map(|b| &b.new_ty).rev().collect::<Vec<_>>();
1428 let prev_new_exprs_reverse = &borrows[0 .. idx].iter().map(|b| &b.new_expr).rev().collect::<Vec<_>>();;
1429 let mut prev_rlt_args = Vec::<syn::Lifetime>::new();
1430 for prev_field in &fields[0 .. idx] {
1431 prev_rlt_args.extend(prev_field.self_rlt_args.iter().cloned());
1432 }
1433 let prev_rlt_args = &prev_rlt_args;
1434
1435 ClosureQuotes {
1436 bound: quote!(for<#(#prev_rlt_args),*> __rental_prelude::FnOnce(#(#prev_new_tys_reverse),*) -> #field_ty),
1437 expr: quote!(#local_name(#(#prev_new_exprs_reverse),*)),
1438 try_bound: quote!(for<#(#prev_rlt_args),*> __rental_prelude::FnOnce(#(#prev_new_tys_reverse),*) -> __rental_prelude::Result<#field_ty, __E>),
1439 try_expr: quote!(#local_name(#(#prev_new_exprs_reverse),*)),
1440 }
1441 } else {
1442 let prev_new_ty = &borrows[idx - 1].new_ty;
1443 let prev_new_expr = &borrows[idx - 1].new_expr;
1444 let prev_rlt_args = &fields[idx - 1].self_rlt_args.iter().chain(&fields[idx - 1].used_rlt_args).collect::<Vec<_>>();
1445
1446 ClosureQuotes {
1447 bound: quote!(for<#(#prev_rlt_args),*> __rental_prelude::FnOnce(#prev_new_ty) -> #field_ty),
1448 expr: quote!(#local_name(#prev_new_expr)),
1449 try_bound: quote!(for<#(#prev_rlt_args),*> __rental_prelude::FnOnce(#prev_new_ty) -> __rental_prelude::Result<#field_ty, __E>),
1450 try_expr: quote!(#local_name(#prev_new_expr)),
1451 }
1452 }
1453 }).collect()
1454 }
1455
1456
1457 struct RentalStructAttribs {
1458 pub doc: Vec<syn::Attribute>,
1459 pub is_rental_mut: bool,
1460 pub is_debug: bool,
1461 pub is_clone: bool,
1462 pub is_deref_suffix: bool,
1463 pub is_deref_mut_suffix: bool,
1464 pub is_covariant: bool,
1465 pub map_suffix_param: Option<syn::TypeParam>,
1466 }
1467
1468
1469 struct RentalField {
1470 pub name: syn::Ident,
1471 pub orig_ty: syn::Type,
1472 pub erased: syn::Field,
1473 pub subrental: Option<Subrental>,
1474 pub self_rlt_args: Vec<syn::Lifetime>,
1475 pub used_rlt_args: Vec<syn::Lifetime>,
1476 pub target_ty_hack: Option<syn::Type>,
1477 pub target_ty_hack_erased: Option<syn::Type>,
1478 }
1479
1480
1481 struct Subrental {
1482 arity: usize,
1483 rental_trait_ident: syn::Ident,
1484 }
1485
1486
1487 struct BorrowQuotes {
1488 pub ty: proc_macro2::TokenStream,
1489 pub ty_hack: proc_macro2::TokenStream,
1490 pub expr: proc_macro2::TokenStream,
1491 pub mut_ty: proc_macro2::TokenStream,
1492 pub mut_ty_hack: proc_macro2::TokenStream,
1493 pub mut_expr: proc_macro2::TokenStream,
1494 pub new_ty: proc_macro2::TokenStream,
1495 pub new_expr: proc_macro2::TokenStream,
1496 }
1497
1498
1499 struct ClosureQuotes {
1500 pub bound: proc_macro2::TokenStream,
1501 pub expr: proc_macro2::TokenStream,
1502 pub try_bound: proc_macro2::TokenStream,
1503 pub try_expr: proc_macro2::TokenStream,
1504 }
1505
1506
1507 struct RentalLifetimeEraser<'a> {
1508 pub fields: &'a [RentalField],
1509 pub used_rlt_args: &'a mut Vec<syn::Lifetime>,
1510 }
1511
1512
1513 impl<'a> syn::fold::Fold for RentalLifetimeEraser<'a> {
fold_lifetime(&mut self, lifetime: syn::Lifetime) -> syn::Lifetime1514 fn fold_lifetime(&mut self, lifetime: syn::Lifetime) -> syn::Lifetime {
1515 let def_site: Span = Span::call_site(); // FIXME: hygiene
1516
1517 if self.fields.iter().any(|field| field.self_rlt_args.contains(&lifetime)) {
1518 if !self.used_rlt_args.contains(&lifetime) {
1519 self.used_rlt_args.push(lifetime.clone());
1520 }
1521
1522 syn::Lifetime::new("'static", def_site)
1523 } else {
1524 lifetime
1525 }
1526 }
1527 }
1528
1529
1530 struct MapTyParamFinder<'p> {
1531 pub ty_param: &'p syn::TypeParam,
1532 pub found: bool,
1533 }
1534
1535
1536 impl<'p, 'ast> syn::visit::Visit<'ast> for MapTyParamFinder<'p> {
visit_path(&mut self, path: &'ast syn::Path)1537 fn visit_path(&mut self, path: &'ast syn::Path) {
1538 if path.leading_colon.is_none() && path.segments.len() == 1 && path.segments[0].ident == self.ty_param.ident && path.segments[0].arguments == syn::PathArguments::None {
1539 self.found = true;
1540 } else {
1541 for seg in &path.segments {
1542 self.visit_path_segment(seg)
1543 };
1544 }
1545 }
1546 }
1547
1548
1549 struct MapTyParamReplacer<'p> {
1550 pub ty_param: &'p syn::TypeParam,
1551 }
1552
1553
1554 impl<'p> syn::fold::Fold for MapTyParamReplacer<'p> {
fold_path(&mut self, path: syn::Path) -> syn::Path1555 fn fold_path(&mut self, path: syn::Path) -> syn::Path {
1556 if path.leading_colon.is_none() && path.segments.len() == 1 && path.segments[0].ident == self.ty_param.ident && path.segments[0].arguments == syn::PathArguments::None {
1557 let def_site: Span = Span::call_site(); // FIXME: hygiene
1558
1559 syn::Path{
1560 leading_colon: None,
1561 segments: syn::punctuated::Punctuated::from_iter(Some(
1562 syn::punctuated::Pair::End(syn::PathSegment{ident: syn::Ident::new("__U", def_site), arguments: syn::PathArguments::None})
1563 )),
1564 }
1565 } else {
1566 let syn::Path{
1567 leading_colon,
1568 segments,
1569 } = path;
1570
1571 syn::Path{
1572 leading_colon: leading_colon,
1573 segments: syn::punctuated::Punctuated::from_iter(segments.into_pairs().map(|p| match p {
1574 syn::punctuated::Pair::Punctuated(seg, punc) => syn::punctuated::Pair::Punctuated(self.fold_path_segment(seg), punc),
1575 syn::punctuated::Pair::End(seg) => syn::punctuated::Pair::End(self.fold_path_segment(seg)),
1576 }))
1577 }
1578 }
1579 }
1580
1581
fold_type_param(&mut self, mut ty_param: syn::TypeParam) -> syn::TypeParam1582 fn fold_type_param(&mut self, mut ty_param: syn::TypeParam) -> syn::TypeParam {
1583 if ty_param.ident == self.ty_param.ident {
1584 let def_site: Span = Span::call_site(); // FIXME: hygiene
1585 ty_param.ident = syn::Ident::new("__U", def_site);
1586 }
1587
1588 let bounds = syn::punctuated::Punctuated::from_iter(ty_param.bounds.iter().map(|b| self.fold_type_param_bound(b.clone())));
1589 ty_param.bounds = bounds;
1590
1591 ty_param
1592 }
1593 }
1594
1595
1596