1 use std::cmp::Ordering;
2 use std::fmt::{self, Display};
3 use std::hash::{Hash, Hasher};
4 
5 use proc_macro2::{Ident, Span};
6 
7 #[cfg(feature = "parsing")]
8 use crate::lookahead;
9 
10 /// A Rust lifetime: `'a`.
11 ///
12 /// Lifetime names must conform to the following rules:
13 ///
14 /// - Must start with an apostrophe.
15 /// - Must not consist of just an apostrophe: `'`.
16 /// - Character after the apostrophe must be `_` or a Unicode code point with
17 ///   the XID_Start property.
18 /// - All following characters must be Unicode code points with the XID_Continue
19 ///   property.
20 ///
21 /// *This type is available only if Syn is built with the `"derive"` or `"full"`
22 /// feature.*
23 #[cfg_attr(feature = "extra-traits", derive(Debug))]
24 #[derive(Clone)]
25 pub struct Lifetime {
26     pub apostrophe: Span,
27     pub ident: Ident,
28 }
29 
30 impl Lifetime {
31     /// # Panics
32     ///
33     /// Panics if the lifetime does not conform to the bulleted rules above.
34     ///
35     /// # Invocation
36     ///
37     /// ```
38     /// # use proc_macro2::Span;
39     /// # use syn::Lifetime;
40     /// #
41     /// # fn f() -> Lifetime {
42     /// Lifetime::new("'a", Span::call_site())
43     /// # }
44     /// ```
new(symbol: &str, span: Span) -> Self45     pub fn new(symbol: &str, span: Span) -> Self {
46         if !symbol.starts_with('\'') {
47             panic!(
48                 "lifetime name must start with apostrophe as in \"'a\", got {:?}",
49                 symbol
50             );
51         }
52 
53         if symbol == "'" {
54             panic!("lifetime name must not be empty");
55         }
56 
57         if !crate::ident::xid_ok(&symbol[1..]) {
58             panic!("{:?} is not a valid lifetime name", symbol);
59         }
60 
61         Lifetime {
62             apostrophe: span,
63             ident: Ident::new(&symbol[1..], span),
64         }
65     }
66 }
67 
68 impl Display for Lifetime {
fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result69     fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
70         "'".fmt(formatter)?;
71         self.ident.fmt(formatter)
72     }
73 }
74 
75 impl PartialEq for Lifetime {
eq(&self, other: &Lifetime) -> bool76     fn eq(&self, other: &Lifetime) -> bool {
77         self.ident.eq(&other.ident)
78     }
79 }
80 
81 impl Eq for Lifetime {}
82 
83 impl PartialOrd for Lifetime {
partial_cmp(&self, other: &Lifetime) -> Option<Ordering>84     fn partial_cmp(&self, other: &Lifetime) -> Option<Ordering> {
85         Some(self.cmp(other))
86     }
87 }
88 
89 impl Ord for Lifetime {
cmp(&self, other: &Lifetime) -> Ordering90     fn cmp(&self, other: &Lifetime) -> Ordering {
91         self.ident.cmp(&other.ident)
92     }
93 }
94 
95 impl Hash for Lifetime {
hash<H: Hasher>(&self, h: &mut H)96     fn hash<H: Hasher>(&self, h: &mut H) {
97         self.ident.hash(h)
98     }
99 }
100 
101 #[cfg(feature = "parsing")]
102 #[doc(hidden)]
103 #[allow(non_snake_case)]
Lifetime(marker: lookahead::TokenMarker) -> Lifetime104 pub fn Lifetime(marker: lookahead::TokenMarker) -> Lifetime {
105     match marker {}
106 }
107 
108 #[cfg(feature = "parsing")]
109 pub mod parsing {
110     use super::*;
111 
112     use crate::parse::{Parse, ParseStream, Result};
113 
114     impl Parse for Lifetime {
parse(input: ParseStream) -> Result<Self>115         fn parse(input: ParseStream) -> Result<Self> {
116             input.step(|cursor| {
117                 cursor
118                     .lifetime()
119                     .ok_or_else(|| cursor.error("expected lifetime"))
120             })
121         }
122     }
123 }
124 
125 #[cfg(feature = "printing")]
126 mod printing {
127     use super::*;
128 
129     use proc_macro2::{Punct, Spacing, TokenStream};
130     use quote::{ToTokens, TokenStreamExt};
131 
132     impl ToTokens for Lifetime {
to_tokens(&self, tokens: &mut TokenStream)133         fn to_tokens(&self, tokens: &mut TokenStream) {
134             let mut apostrophe = Punct::new('\'', Spacing::Joint);
135             apostrophe.set_span(self.apostrophe);
136             tokens.append(apostrophe);
137             self.ident.to_tokens(tokens);
138         }
139     }
140 }
141