abi_stable_derive/sabi_trait/
lifetime_unelider.rs1use syn::{
2 visit_mut::{self, VisitMut},
3 Lifetime, Type, TypeReference,
4};
5
6pub(crate) struct LifetimeUnelider<'a, 'b> {
8 self_lifetime: &'b mut Option<&'a syn::Lifetime>,
9 contains_self_borrow: bool,
10 pub(crate) additional_lifetime_def: Option<&'a syn::LifetimeDef>,
11}
12
13pub(crate) struct TypeProperties<'a> {
14 pub(crate) additional_lifetime_def: Option<&'a syn::LifetimeDef>,
15 pub(crate) found_borrow_kind: Option<BorrowKind>,
16}
17
18#[derive(Debug, Clone, PartialEq, Eq)]
19pub(crate) enum BorrowKind {
20 Reference,
21 MutReference,
22 Other,
23}
24
25impl<'a, 'b> LifetimeUnelider<'a, 'b> {
26 pub(crate) fn new(self_lifetime: &'b mut Option<&'a syn::Lifetime>) -> Self {
27 Self {
28 self_lifetime,
29 contains_self_borrow: false,
30 additional_lifetime_def: None,
31 }
32 }
33
34 pub(crate) fn visit_type(mut self, ty: &mut Type) -> TypeProperties<'a> {
36 self.contains_self_borrow = false;
37
38 visit_mut::visit_type_mut(&mut self, ty);
39
40 let found_borrow_kind = if self.contains_self_borrow {
41 let bk = match &*ty {
42 Type::Reference(tr) => {
43 if tr.mutability.is_some() {
44 BorrowKind::MutReference
45 } else {
46 BorrowKind::Reference
47 }
48 }
49 _ => BorrowKind::Other,
50 };
51
52 Some(bk)
53 } else {
54 None
55 };
56
57 TypeProperties {
58 additional_lifetime_def: self.additional_lifetime_def,
59 found_borrow_kind,
60 }
61 }
62}
63
64impl<'a, 'b> LifetimeUnelider<'a, 'b> {
65 fn setup_lifetime(&mut self) -> Lifetime {
66 let additional_lifetime_def = &mut self.additional_lifetime_def;
67 let x = self.self_lifetime.get_or_insert_with(|| {
68 let ret = syn::parse_str::<syn::LifetimeDef>("'_self").unwrap();
69 let ret: &'a syn::LifetimeDef = Box::leak(Box::new(ret));
70 *additional_lifetime_def = Some(ret);
71 &ret.lifetime
72 });
73 (*x).clone()
74 }
75}
76impl<'a, 'b> VisitMut for LifetimeUnelider<'a, 'b> {
77 fn visit_type_reference_mut(&mut self, ref_: &mut TypeReference) {
78 if is_self_borrow(self.self_lifetime, ref_) {
79 self.contains_self_borrow = true;
80 }
81
82 let is_elided = ref_.lifetime.as_ref().map_or(true, |x| x.ident == "_");
83
84 if is_elided {
85 ref_.lifetime = Some(self.setup_lifetime());
86 }
87
88 visit_mut::visit_type_mut(self, &mut ref_.elem)
89 }
90
91 fn visit_lifetime_mut(&mut self, lt: &mut Lifetime) {
92 if is_self_lifetime(self.self_lifetime, lt) {
93 self.contains_self_borrow = true;
94 }
95
96 if lt.ident == "_" {
97 *lt = self.setup_lifetime();
98 }
99 }
100}
101
102fn is_self_lifetime(self_lifetime: &Option<&Lifetime>, lt: &Lifetime) -> bool {
103 match self_lifetime {
104 Some(sl) if sl.ident == lt.ident => true,
105 _ => lt.ident == "_",
106 }
107}
108
109fn is_self_borrow(self_lifetime: &Option<&Lifetime>, tr: &TypeReference) -> bool {
110 match (self_lifetime, &tr.lifetime) {
111 (Some(sl), Some(lt)) if sl.ident == lt.ident => true,
112 (_, Some(lt)) => lt.ident == "_",
113 (_, None) => true,
114 }
115}
116
117#[cfg(test)]
118mod tests {
119 use super::*;
120
121 fn get_self_borrow_kind<'a, 'b>(
122 mut self_lifetime: Option<&'a syn::Lifetime>,
123 mut ty: Type,
124 ) -> Option<BorrowKind> {
125 let mut this = LifetimeUnelider::new(&mut self_lifetime);
126 let ret = this.visit_type(&mut ty.clone());
127 ret.found_borrow_kind
128 }
129
130 fn assert_elided(self_lifetime: &Lifetime, ty: Type, expected: BorrowKind) {
131 assert_eq!(
132 get_self_borrow_kind(Some(self_lifetime), ty.clone()),
133 Some(expected.clone())
134 );
135 assert_eq!(get_self_borrow_kind(None, ty.clone()), Some(expected));
136 }
137
138 fn assert_unelided(self_lifetime: &Lifetime, ty: Type, expected: BorrowKind) {
139 assert_eq!(
140 get_self_borrow_kind(Some(self_lifetime), ty.clone()),
141 Some(expected.clone())
142 );
143 assert_eq!(get_self_borrow_kind(None, ty.clone()), None);
144 }
145
146 fn parse_ty(s: &str) -> syn::Type {
147 syn::parse_str(s).unwrap()
148 }
149
150 #[test]
151 fn borrow_self_detection() {
152 let lifetime_a = &syn::parse_str::<Lifetime>("'a").unwrap();
153
154 {
156 assert_elided(lifetime_a, parse_ty("&()"), BorrowKind::Reference);
157 assert_elided(lifetime_a, parse_ty("&mut ()"), BorrowKind::MutReference);
158 assert_elided(lifetime_a, parse_ty("Option<&()>"), BorrowKind::Other);
159 assert_elided(lifetime_a, parse_ty("Option<&mut ()>"), BorrowKind::Other);
160 assert_elided(lifetime_a, parse_ty("Foo<'_>"), BorrowKind::Other);
161
162 assert_elided(lifetime_a, parse_ty("&'_ &'b ()"), BorrowKind::Reference);
163 assert_elided(
164 lifetime_a,
165 parse_ty("&'_ mut &'b ()"),
166 BorrowKind::MutReference,
167 );
168 assert_elided(lifetime_a, parse_ty("&'b &'_ ()"), BorrowKind::Reference);
169 assert_elided(
170 lifetime_a,
171 parse_ty("&'b mut &'_ ()"),
172 BorrowKind::MutReference,
173 );
174
175 assert_elided(
176 lifetime_a,
177 parse_ty("Option<&'_ &'b ()>"),
178 BorrowKind::Other,
179 );
180 assert_elided(
181 lifetime_a,
182 parse_ty("Option<&'_ mut &'b ()>"),
183 BorrowKind::Other,
184 );
185 assert_elided(
186 lifetime_a,
187 parse_ty("Option<&'b &'_ ()>"),
188 BorrowKind::Other,
189 );
190 assert_elided(
191 lifetime_a,
192 parse_ty("Option<&'b mut &'_ ()>"),
193 BorrowKind::Other,
194 );
195 }
196
197 {
199 assert_unelided(lifetime_a, parse_ty("&'a ()"), BorrowKind::Reference);
200 assert_unelided(lifetime_a, parse_ty("&'a mut ()"), BorrowKind::MutReference);
201 assert_unelided(lifetime_a, parse_ty("Option<&'a ()>"), BorrowKind::Other);
202 assert_unelided(
203 lifetime_a,
204 parse_ty("Option<&'a mut ()>"),
205 BorrowKind::Other,
206 );
207 assert_unelided(lifetime_a, parse_ty("Foo<'a>"), BorrowKind::Other);
208
209 assert_unelided(lifetime_a, parse_ty("&'a &'b ()"), BorrowKind::Reference);
210 assert_unelided(
211 lifetime_a,
212 parse_ty("&'a mut &'b ()"),
213 BorrowKind::MutReference,
214 );
215 assert_unelided(lifetime_a, parse_ty("&'b &'a ()"), BorrowKind::Reference);
216 assert_unelided(
217 lifetime_a,
218 parse_ty("&'b mut &'a ()"),
219 BorrowKind::MutReference,
220 );
221
222 assert_unelided(
223 lifetime_a,
224 parse_ty("Option<&'a &'b ()>"),
225 BorrowKind::Other,
226 );
227 assert_unelided(
228 lifetime_a,
229 parse_ty("Option<&'a mut &'b ()>"),
230 BorrowKind::Other,
231 );
232 assert_unelided(
233 lifetime_a,
234 parse_ty("Option<&'b &'a ()>"),
235 BorrowKind::Other,
236 );
237 assert_unelided(
238 lifetime_a,
239 parse_ty("Option<&'b mut &'a ()>"),
240 BorrowKind::Other,
241 );
242 }
243
244 {
245 let gsbk = get_self_borrow_kind;
246 let lt_a = Some(lifetime_a);
247 assert_eq!(gsbk(lt_a, parse_ty("&'b ()")), None);
248 assert_eq!(gsbk(lt_a, parse_ty("&'b mut ()")), None);
249 assert_eq!(gsbk(lt_a, parse_ty("Option<&'b ()>")), None);
250 assert_eq!(gsbk(lt_a, parse_ty("Option<&'b mut ()>")), None);
251 assert_eq!(gsbk(lt_a, parse_ty("Foo<'b>")), None);
252 }
253 }
254}