1#[cfg(feature = "parsing")]
2use crate::lookahead;
3#[cfg(feature = "parsing")]
4use crate::parse::{ParseStream, Result};
5use core::cmp::Ordering;
6use core::fmt::{self, Display};
7use core::hash::{Hash, Hasher};
8use proc_macro2::{Ident, Span};
9
10pub struct Lifetime {
21 pub apostrophe: Span,
22 pub ident: Ident,
23}
24
25impl Lifetime {
26 pub fn new(symbol: &str, span: Span) -> Self {
41 let ident = match symbol.strip_prefix('\'') {
42 Some(ident) => ident,
43 None => {
::core::panicking::panic_fmt(format_args!("lifetime name must start with apostrophe as in \"\'a\", got {0:?}",
symbol));
}panic!(
44 "lifetime name must start with apostrophe as in \"'a\", got {:?}",
45 symbol,
46 ),
47 };
48
49 let unraw = ident.strip_prefix("r#");
50 let validate = unraw.unwrap_or(ident);
51 if validate.is_empty() {
52 {
::core::panicking::panic_fmt(format_args!("lifetime name must not be empty"));
};panic!("lifetime name must not be empty");
53 }
54 if !crate::ident::xid_ok(validate) {
55 {
::core::panicking::panic_fmt(format_args!("{0:?} is not a valid lifetime name",
symbol));
};panic!("{:?} is not a valid lifetime name", symbol);
56 }
57
58 Lifetime {
59 apostrophe: span,
60 ident: match unraw {
61 Some(unraw) => Ident::new_raw(unraw, span),
62 None => Ident::new(ident, span),
63 },
64 }
65 }
66
67 pub fn span(&self) -> Span {
68 self.apostrophe
69 .join(self.ident.span())
70 .unwrap_or(self.apostrophe)
71 }
72
73 pub fn set_span(&mut self, span: Span) {
74 self.apostrophe = span;
75 self.ident.set_span(span);
76 }
77
78 #[cfg(feature = "parsing")]
79 #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))]
80 pub fn parse_any(input: ParseStream) -> Result<Self> {
81 input.step(|cursor| match cursor.lifetime() {
82 Some((lifetime, rest)) => Ok((lifetime, rest)),
83 None => Err(cursor.error("expected lifetime")),
84 })
85 }
86}
87
88impl Display for Lifetime {
89 fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
90 "'".fmt(formatter)?;
91 self.ident.fmt(formatter)
92 }
93}
94
95impl Clone for Lifetime {
96 fn clone(&self) -> Self {
97 Lifetime {
98 apostrophe: self.apostrophe,
99 ident: self.ident.clone(),
100 }
101 }
102}
103
104impl PartialEq for Lifetime {
105 fn eq(&self, other: &Lifetime) -> bool {
106 self.ident.eq(&other.ident)
107 }
108}
109
110impl Eq for Lifetime {}
111
112impl PartialOrd for Lifetime {
113 fn partial_cmp(&self, other: &Lifetime) -> Option<Ordering> {
114 Some(self.cmp(other))
115 }
116}
117
118impl Ord for Lifetime {
119 fn cmp(&self, other: &Lifetime) -> Ordering {
120 self.ident.cmp(&other.ident)
121 }
122}
123
124impl Hash for Lifetime {
125 fn hash<H: Hasher>(&self, h: &mut H) {
126 self.ident.hash(h);
127 }
128}
129
130#[cfg(feature = "parsing")]
131#[doc(hidden)]
#[allow(non_snake_case)]
pub(crate) fn Lifetime(marker: lookahead::TokenMarker) -> Lifetime {
match marker {}
}pub_if_not_doc! {
132 #[doc(hidden)]
133 #[allow(non_snake_case)]
134 pub fn Lifetime(marker: lookahead::TokenMarker) -> Lifetime {
135 match marker {}
136 }
137}
138
139#[cfg(feature = "parsing")]
140pub(crate) mod parsing {
141 use crate::error::Result;
142 use crate::ident;
143 use crate::lifetime::Lifetime;
144 use crate::parse::{Parse, ParseStream};
145 use alloc::string::ToString;
146
147 #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))]
148 impl Parse for Lifetime {
149 fn parse(input: ParseStream) -> Result<Self> {
150 input.step(|cursor| {
151 if let Some((lifetime, rest)) = cursor.lifetime() {
152 let repr = lifetime.ident.to_string();
153 if ident::parsing::accept_as_ident(&repr) || repr == "static" || repr == "_" {
154 Ok((lifetime, rest))
155 } else {
156 Err(cursor
157 .error(format_args!("unexpected keyword lifetime \"{0}\"", lifetime)format_args!("unexpected keyword lifetime \"{}\"", lifetime)))
158 }
159 } else {
160 Err(cursor.error("expected lifetime"))
161 }
162 })
163 }
164 }
165
166 impl Lifetime {
167 #[cfg(any(feature = "full", feature = "derive"))]
168 pub(crate) fn parse_optional_any(input: ParseStream) -> Option<Self> {
169 input
170 .step(|cursor| match cursor.lifetime() {
171 Some((lifetime, rest)) => Ok((Some(lifetime), rest)),
172 None => Ok((None, *cursor)),
173 })
174 .unwrap()
175 }
176 }
177}
178
179#[cfg(feature = "printing")]
180mod printing {
181 use crate::ext::PunctExt as _;
182 use crate::lifetime::Lifetime;
183 use proc_macro2::{Punct, Spacing, TokenStream};
184 use quote::{ToTokens, TokenStreamExt as _};
185
186 #[cfg_attr(docsrs, doc(cfg(feature = "printing")))]
187 impl ToTokens for Lifetime {
188 fn to_tokens(&self, tokens: &mut TokenStream) {
189 tokens.append(Punct::new_spanned('\'', Spacing::Joint, self.apostrophe));
190 self.ident.to_tokens(tokens);
191 }
192 }
193}