Linux kernel mirror (for testing)
git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel
os
linux
1// SPDX-License-Identifier: Apache-2.0 OR MIT
2
3#[cfg(feature = "parsing")]
4use crate::lookahead;
5use proc_macro2::{Ident, Span};
6use std::cmp::Ordering;
7use std::fmt::{self, Display};
8use std::hash::{Hash, Hasher};
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.
20pub struct Lifetime {
21 pub apostrophe: Span,
22 pub ident: Ident,
23}
24
25impl Lifetime {
26 /// # Panics
27 ///
28 /// Panics if the lifetime does not conform to the bulleted rules above.
29 ///
30 /// # Invocation
31 ///
32 /// ```
33 /// # use proc_macro2::Span;
34 /// # use syn::Lifetime;
35 /// #
36 /// # fn f() -> Lifetime {
37 /// Lifetime::new("'a", Span::call_site())
38 /// # }
39 /// ```
40 pub fn new(symbol: &str, span: Span) -> Self {
41 if !symbol.starts_with('\'') {
42 panic!(
43 "lifetime name must start with apostrophe as in \"'a\", got {:?}",
44 symbol
45 );
46 }
47
48 if symbol == "'" {
49 panic!("lifetime name must not be empty");
50 }
51
52 if !crate::ident::xid_ok(&symbol[1..]) {
53 panic!("{:?} is not a valid lifetime name", symbol);
54 }
55
56 Lifetime {
57 apostrophe: span,
58 ident: Ident::new(&symbol[1..], span),
59 }
60 }
61
62 pub fn span(&self) -> Span {
63 self.apostrophe
64 .join(self.ident.span())
65 .unwrap_or(self.apostrophe)
66 }
67
68 pub fn set_span(&mut self, span: Span) {
69 self.apostrophe = span;
70 self.ident.set_span(span);
71 }
72}
73
74impl Display for Lifetime {
75 fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
76 "'".fmt(formatter)?;
77 self.ident.fmt(formatter)
78 }
79}
80
81impl Clone for Lifetime {
82 fn clone(&self) -> Self {
83 Lifetime {
84 apostrophe: self.apostrophe,
85 ident: self.ident.clone(),
86 }
87 }
88}
89
90impl PartialEq for Lifetime {
91 fn eq(&self, other: &Lifetime) -> bool {
92 self.ident.eq(&other.ident)
93 }
94}
95
96impl Eq for Lifetime {}
97
98impl PartialOrd for Lifetime {
99 fn partial_cmp(&self, other: &Lifetime) -> Option<Ordering> {
100 Some(self.cmp(other))
101 }
102}
103
104impl Ord for Lifetime {
105 fn cmp(&self, other: &Lifetime) -> Ordering {
106 self.ident.cmp(&other.ident)
107 }
108}
109
110impl Hash for Lifetime {
111 fn hash<H: Hasher>(&self, h: &mut H) {
112 self.ident.hash(h);
113 }
114}
115
116#[cfg(feature = "parsing")]
117pub_if_not_doc! {
118 #[doc(hidden)]
119 #[allow(non_snake_case)]
120 pub fn Lifetime(marker: lookahead::TokenMarker) -> Lifetime {
121 match marker {}
122 }
123}
124
125#[cfg(feature = "parsing")]
126pub(crate) mod parsing {
127 use crate::error::Result;
128 use crate::lifetime::Lifetime;
129 use crate::parse::{Parse, ParseStream};
130
131 #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))]
132 impl Parse for Lifetime {
133 fn parse(input: ParseStream) -> Result<Self> {
134 input.step(|cursor| {
135 cursor
136 .lifetime()
137 .ok_or_else(|| cursor.error("expected lifetime"))
138 })
139 }
140 }
141}
142
143#[cfg(feature = "printing")]
144mod printing {
145 use crate::lifetime::Lifetime;
146 use proc_macro2::{Punct, Spacing, TokenStream};
147 use quote::{ToTokens, TokenStreamExt};
148
149 #[cfg_attr(docsrs, doc(cfg(feature = "printing")))]
150 impl ToTokens for Lifetime {
151 fn to_tokens(&self, tokens: &mut TokenStream) {
152 let mut apostrophe = Punct::new('\'', Spacing::Joint);
153 apostrophe.set_span(self.apostrophe);
154 tokens.append(apostrophe);
155 self.ident.to_tokens(tokens);
156 }
157 }
158}