Skip to main content

yoke_derive/
lifetimes.rs

1// This file is part of ICU4X. For terms of use, please see the file
2// called LICENSE at the top level of the ICU4X source tree
3// (online at: https://github.com/unicode-org/icu4x/blob/main/LICENSE ).
4
5use proc_macro2::Span;
6use syn::ext::IdentExt as _;
7use syn::{Ident, Lifetime, Type};
8
9pub fn static_lt() -> Lifetime {
10    Lifetime::new("'static", Span::call_site())
11}
12
13pub fn custom_lt(s: &str) -> Lifetime {
14    Lifetime::new(s, Span::call_site())
15}
16
17/// The returned ident should not be used in a way that impacts the code generated by the derive.
18pub fn ignored_lifetime_ident() -> Ident {
19    Ident::new("_does_not_matter", Span::call_site())
20}
21
22/// `lt_param` is the un-raw version of the lifetime parameter of the yokeable type.
23/// This function replaces all (possibly raw) occurrences of `lt_param` in the type `x` with the
24/// `lt` lifetime.
25pub fn replace_lifetime(lt_param: &Ident, x: &Type, lt: Lifetime) -> Type {
26    use syn::fold::Fold;
27    struct ReplaceLifetime<'a>(&'a Ident, Lifetime);
28
29    impl Fold for ReplaceLifetime<'_> {
30        fn fold_lifetime(&mut self, lt: Lifetime) -> Lifetime {
31            if lt.ident.unraw() == *self.0 {
32                // Note that `for<>` binders cannot introduce a lifetime already in scope,
33                // so `lt.ident` necessarily refers to the lifetime parameter of the yokeable.
34                self.1.clone()
35            } else {
36                lt
37            }
38        }
39    }
40    ReplaceLifetime(lt_param, lt).fold_type(x.clone())
41}
42
43#[cfg(test)]
44mod tests {
45    use proc_macro2::Span;
46    use syn::{parse_quote, Ident};
47
48    use super::{custom_lt, replace_lifetime};
49
50    fn a_ident() -> Ident {
51        Ident::new("a", Span::call_site())
52    }
53
54    fn b_ident() -> Ident {
55        Ident::new("b", Span::call_site())
56    }
57
58    #[test]
59    fn replace_lt_static() {
60        assert_eq!(
61            replace_lifetime(&a_ident(), &parse_quote!(Foo<'static, T>), custom_lt("'a")),
62            parse_quote!(Foo<'static, T>),
63        );
64
65        assert_eq!(
66            replace_lifetime(&a_ident(), &parse_quote!(Foo<'a, T>), custom_lt("'static")),
67            parse_quote!(Foo<'static, T>),
68        );
69    }
70
71    #[test]
72    fn replace_lt_ab() {
73        // Probably shouldn't happen in actual use cases, but still works
74        assert_eq!(
75            replace_lifetime(&a_ident(), &parse_quote!(Foo<'a, 'b, T>), custom_lt("'c")),
76            parse_quote!(Foo<'c, 'b, T>),
77        );
78
79        assert_eq!(
80            replace_lifetime(
81                &b_ident(),
82                &parse_quote!(for<'a> fn(fn(Foo<'a, 'b, T>))),
83                custom_lt("'c"),
84            ),
85            parse_quote!(for<'a> fn(fn(Foo<'a, 'c, T>))),
86        );
87    }
88
89    #[test]
90    fn replace_lt_macro() {
91        assert_eq!(
92            replace_lifetime(&a_ident(), &parse_quote!(foo!(Foo<'a, T>)), custom_lt("'b")),
93            parse_quote!(foo!(Foo<'a, T>)),
94        );
95
96        assert_eq!(
97            replace_lifetime(&a_ident(), &parse_quote!(Foo<'a, foo!(T)>), custom_lt("'b")),
98            parse_quote!(Foo<'b, foo!(T)>),
99        );
100
101        assert_eq!(
102            replace_lifetime(&a_ident(), &parse_quote!(Foo<foo!('a), T>), custom_lt("'b")),
103            parse_quote!(Foo<foo!('a), T>),
104        );
105    }
106
107    #[test]
108    fn replace_raw() {
109        assert_eq!(
110            replace_lifetime(&a_ident(), &parse_quote!(Foo<'r#a, T>), custom_lt("'b")),
111            parse_quote!(Foo<'b, T>),
112        );
113    }
114}