yew_macro/hook/
lifetime.rs1use std::sync::{Arc, Mutex};
2
3use proc_macro2::Span;
4use syn::visit_mut::{self, VisitMut};
5use syn::{
6 GenericArgument, Lifetime, ParenthesizedGenericArguments, Receiver, TypeBareFn, TypeImplTrait,
7 TypeParamBound, TypeReference, TypeTraitObject,
8};
9
10pub struct CollectLifetimes {
12 pub elided: Vec<Lifetime>,
13 pub name: &'static str,
14 pub default_span: Span,
15
16 pub type_trait_obj_lock: Arc<Mutex<()>>,
17 pub impl_trait_lock: Arc<Mutex<()>>,
18 pub impl_fn_lock: Arc<Mutex<()>>,
19}
20
21impl CollectLifetimes {
22 pub fn new(name: &'static str, default_span: Span) -> Self {
23 CollectLifetimes {
24 elided: Vec::new(),
25 name,
26 default_span,
27
28 impl_trait_lock: Arc::default(),
29 type_trait_obj_lock: Arc::default(),
30 impl_fn_lock: Arc::default(),
31 }
32 }
33
34 fn is_impl_trait(&self) -> bool {
35 self.impl_trait_lock.try_lock().is_err()
36 }
37
38 fn is_type_trait_obj(&self) -> bool {
39 self.type_trait_obj_lock.try_lock().is_err()
40 }
41
42 fn is_impl_fn(&self) -> bool {
43 self.impl_fn_lock.try_lock().is_err()
44 }
45
46 fn visit_opt_lifetime(&mut self, lifetime: &mut Option<Lifetime>) {
47 match lifetime {
48 None => *lifetime = Some(self.next_lifetime(None)),
49 Some(lifetime) => self.visit_lifetime(lifetime),
50 }
51 }
52
53 fn visit_lifetime(&mut self, lifetime: &mut Lifetime) {
54 if lifetime.ident == "_" {
55 *lifetime = self.next_lifetime(lifetime.span());
56 }
57 }
58
59 fn next_lifetime<S: Into<Option<Span>>>(&mut self, span: S) -> Lifetime {
60 let name = format!("{}{}", self.name, self.elided.len());
61 let span = span.into().unwrap_or(self.default_span);
62 let life = Lifetime::new(&name, span);
63 self.elided.push(life.clone());
64 life
65 }
66}
67
68impl VisitMut for CollectLifetimes {
69 fn visit_receiver_mut(&mut self, arg: &mut Receiver) {
70 if let Some((_, lifetime)) = &mut arg.reference {
71 self.visit_opt_lifetime(lifetime);
72 }
73 }
74
75 fn visit_type_reference_mut(&mut self, ty: &mut TypeReference) {
76 if self.is_impl_fn() {
78 return;
79 }
80
81 self.visit_opt_lifetime(&mut ty.lifetime);
82 visit_mut::visit_type_reference_mut(self, ty);
83 }
84
85 fn visit_generic_argument_mut(&mut self, gen: &mut GenericArgument) {
86 if self.is_impl_fn() {
88 return;
89 }
90
91 if let GenericArgument::Lifetime(lifetime) = gen {
92 self.visit_lifetime(lifetime);
93 }
94 visit_mut::visit_generic_argument_mut(self, gen);
95 }
96
97 fn visit_type_impl_trait_mut(&mut self, impl_trait: &mut TypeImplTrait) {
98 let impl_trait_lock = self.impl_trait_lock.clone();
99 let _locked = impl_trait_lock.try_lock();
100
101 impl_trait
102 .bounds
103 .insert(0, TypeParamBound::Lifetime(self.next_lifetime(None)));
104
105 visit_mut::visit_type_impl_trait_mut(self, impl_trait);
106 }
107
108 fn visit_type_trait_object_mut(&mut self, type_trait_obj: &mut TypeTraitObject) {
109 let type_trait_obj_lock = self.type_trait_obj_lock.clone();
110 let _locked = type_trait_obj_lock.try_lock();
111
112 visit_mut::visit_type_trait_object_mut(self, type_trait_obj);
113 }
114
115 fn visit_parenthesized_generic_arguments_mut(
116 &mut self,
117 generic_args: &mut ParenthesizedGenericArguments,
118 ) {
119 let impl_fn_lock = self.impl_fn_lock.clone();
120 let _maybe_locked =
121 (self.is_impl_trait() || self.is_type_trait_obj()).then(|| impl_fn_lock.try_lock());
122
123 visit_mut::visit_parenthesized_generic_arguments_mut(self, generic_args);
124 }
125
126 fn visit_type_bare_fn_mut(&mut self, i: &mut TypeBareFn) {
127 let impl_fn_lock = self.impl_fn_lock.clone();
128 let _locked = impl_fn_lock.try_lock();
129
130 visit_mut::visit_type_bare_fn_mut(self, i);
131 }
132}