This is unreleased documentation for Yew Next version.
For up-to-date documentation, see the latest version on docs.rs.

yew_macro/hook/
lifetime.rs

1use 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
10// borrowed from the awesome async-trait crate.
11pub 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        // We don't rewrite references in the impl FnOnce(&arg) or fn(&arg)
77        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        // We don't rewrite types in the impl FnOnce(&arg) -> Type<'_>
87        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}