blob: 26f9baccc0c330a395f24c7b9291e69e32099c73 [file] [log] [blame]
David Tolnay63e3dee2017-06-03 20:13:17 -07001use std::cmp::Ordering;
2use std::fmt::{self, Display};
3use std::hash::{Hash, Hasher};
4
David Tolnay65fb5662018-05-20 20:02:28 -07005use proc_macro2::{Ident, Span};
David Tolnay63e3dee2017-06-03 20:13:17 -07006use unicode_xid::UnicodeXID;
7
David Tolnay4fb71232018-08-25 23:14:50 -04008#[cfg(feature = "parsing")]
9use lookahead;
Alex Crichton131308c2018-05-18 14:00:24 -070010
David Tolnay05658502018-01-07 09:56:37 -080011/// A Rust lifetime: `'a`.
12///
13/// Lifetime names must conform to the following rules:
14///
15/// - Must start with an apostrophe.
16/// - Must not consist of just an apostrophe: `'`.
David Tolnay05658502018-01-07 09:56:37 -080017/// - Character after the apostrophe must be `_` or a Unicode code point with
18/// the XID_Start property.
19/// - All following characters must be Unicode code points with the XID_Continue
20/// property.
David Tolnay461d98e2018-01-07 11:07:19 -080021///
22/// *This type is available if Syn is built with the `"derive"` or `"full"`
23/// feature.*
David Tolnay63e3dee2017-06-03 20:13:17 -070024#[cfg_attr(feature = "extra-traits", derive(Debug))]
Alex Crichtona74a1c82018-05-16 10:20:44 -070025#[derive(Clone)]
David Tolnay63e3dee2017-06-03 20:13:17 -070026pub struct Lifetime {
David Tolnay78612672018-08-31 08:47:41 -070027 pub apostrophe: Span,
Alex Crichton131308c2018-05-18 14:00:24 -070028 pub ident: Ident,
David Tolnay63e3dee2017-06-03 20:13:17 -070029}
30
31impl Lifetime {
David Tolnay092e21a2018-09-01 16:48:52 -070032 /// # Panics
33 ///
34 /// Panics if the lifetime does not conform to the bulleted rules above.
35 ///
36 /// # Invocation
37 ///
David Tolnay95989db2019-01-01 15:05:57 -050038 /// ```edition2018
David Tolnay092e21a2018-09-01 16:48:52 -070039 /// # extern crate proc_macro2;
David Tolnay092e21a2018-09-01 16:48:52 -070040 /// #
41 /// # use proc_macro2::Span;
42 /// # use syn::Lifetime;
43 /// #
44 /// # fn f() -> Lifetime {
45 /// Lifetime::new("'a", Span::call_site())
46 /// # }
47 /// ```
48 pub fn new(symbol: &str, span: Span) -> Self {
49 if !symbol.starts_with('\'') {
David Tolnay51382052017-12-27 13:46:21 -050050 panic!(
David Tolnay76178be2018-07-31 23:06:15 -070051 "lifetime name must start with apostrophe as in \"'a\", got {:?}",
David Tolnay092e21a2018-09-01 16:48:52 -070052 symbol
David Tolnay51382052017-12-27 13:46:21 -050053 );
David Tolnay63e3dee2017-06-03 20:13:17 -070054 }
55
David Tolnay092e21a2018-09-01 16:48:52 -070056 if symbol == "'" {
David Tolnay63e3dee2017-06-03 20:13:17 -070057 panic!("lifetime name must not be empty");
58 }
59
David Tolnay092e21a2018-09-01 16:48:52 -070060 fn xid_ok(symbol: &str) -> bool {
61 let mut chars = symbol.chars();
David Tolnay63e3dee2017-06-03 20:13:17 -070062 let first = chars.next().unwrap();
63 if !(UnicodeXID::is_xid_start(first) || first == '_') {
64 return false;
65 }
66 for ch in chars {
67 if !UnicodeXID::is_xid_continue(ch) {
68 return false;
69 }
70 }
71 true
72 }
73
David Tolnay092e21a2018-09-01 16:48:52 -070074 if !xid_ok(&symbol[1..]) {
75 panic!("{:?} is not a valid lifetime name", symbol);
David Tolnay63e3dee2017-06-03 20:13:17 -070076 }
77
78 Lifetime {
David Tolnaya19a8192018-09-01 02:36:16 -070079 apostrophe: span,
David Tolnay092e21a2018-09-01 16:48:52 -070080 ident: Ident::new(&symbol[1..], span),
David Tolnay63e3dee2017-06-03 20:13:17 -070081 }
82 }
83}
84
85impl Display for Lifetime {
86 fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
Alex Crichtona74a1c82018-05-16 10:20:44 -070087 "'".fmt(formatter)?;
88 self.ident.fmt(formatter)
David Tolnay63e3dee2017-06-03 20:13:17 -070089 }
90}
91
92impl PartialEq for Lifetime {
93 fn eq(&self, other: &Lifetime) -> bool {
Alex Crichtona74a1c82018-05-16 10:20:44 -070094 self.ident.eq(&other.ident)
David Tolnay63e3dee2017-06-03 20:13:17 -070095 }
96}
97
98impl Eq for Lifetime {}
99
100impl PartialOrd for Lifetime {
101 fn partial_cmp(&self, other: &Lifetime) -> Option<Ordering> {
102 Some(self.cmp(other))
103 }
104}
105
106impl Ord for Lifetime {
107 fn cmp(&self, other: &Lifetime) -> Ordering {
Alex Crichtona74a1c82018-05-16 10:20:44 -0700108 self.ident.cmp(&other.ident)
David Tolnay63e3dee2017-06-03 20:13:17 -0700109 }
110}
111
112impl Hash for Lifetime {
113 fn hash<H: Hasher>(&self, h: &mut H) {
Alex Crichtona74a1c82018-05-16 10:20:44 -0700114 self.ident.hash(h)
David Tolnay63e3dee2017-06-03 20:13:17 -0700115 }
116}
117
118#[cfg(feature = "parsing")]
David Tolnay4fb71232018-08-25 23:14:50 -0400119#[doc(hidden)]
120#[allow(non_snake_case)]
121pub fn Lifetime(marker: lookahead::TokenMarker) -> Lifetime {
122 match marker {}
123}
124
125#[cfg(feature = "parsing")]
David Tolnay63e3dee2017-06-03 20:13:17 -0700126pub mod parsing {
127 use super::*;
David Tolnay94d304f2018-08-30 23:43:53 -0700128
David Tolnay78612672018-08-31 08:47:41 -0700129 use parse::{Parse, ParseStream, Result};
David Tolnay63e3dee2017-06-03 20:13:17 -0700130
David Tolnay7744d9d2018-08-25 22:15:52 -0400131 impl Parse for Lifetime {
132 fn parse(input: ParseStream) -> Result<Self> {
David Tolnay66cb0c42018-08-31 09:01:30 -0700133 input.step(|cursor| {
134 cursor
135 .lifetime()
136 .ok_or_else(|| cursor.error("expected lifetime"))
David Tolnay7744d9d2018-08-25 22:15:52 -0400137 })
Sergio Benitez5680d6a2017-12-29 11:20:29 -0800138 }
David Tolnay63e3dee2017-06-03 20:13:17 -0700139 }
140}
141
142#[cfg(feature = "printing")]
143mod printing {
144 use super::*;
David Tolnay78612672018-08-31 08:47:41 -0700145
146 use proc_macro2::{Punct, Spacing, TokenStream};
147 use quote::{ToTokens, TokenStreamExt};
David Tolnay63e3dee2017-06-03 20:13:17 -0700148
149 impl ToTokens for Lifetime {
Alex Crichtona74a1c82018-05-16 10:20:44 -0700150 fn to_tokens(&self, tokens: &mut TokenStream) {
David Tolnay78612672018-08-31 08:47:41 -0700151 let mut apostrophe = Punct::new('\'', Spacing::Joint);
152 apostrophe.set_span(self.apostrophe);
153 tokens.append(apostrophe);
Alex Crichtona74a1c82018-05-16 10:20:44 -0700154 self.ident.to_tokens(tokens);
David Tolnay63e3dee2017-06-03 20:13:17 -0700155 }
156 }
157}