blob: 65f3f37943ec98bf27ff03d87f4d6322a2d78163 [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 Tolnay98942562017-12-26 21:24:35 -05005use proc_macro2::{Span, Term};
David Tolnay63e3dee2017-06-03 20:13:17 -07006use unicode_xid::UnicodeXID;
7
David Tolnay63e3dee2017-06-03 20:13:17 -07008#[cfg_attr(feature = "extra-traits", derive(Debug))]
9#[cfg_attr(feature = "clone-impls", derive(Clone))]
10pub struct Lifetime {
David Tolnay73c98de2017-12-31 15:56:56 -050011 term: Term,
David Tolnay63e3dee2017-06-03 20:13:17 -070012 pub span: Span,
13}
14
15impl Lifetime {
David Tolnay73c98de2017-12-31 15:56:56 -050016 pub fn new(term: Term, span: Span) -> Self {
17 let s = term.as_str();
David Tolnay63e3dee2017-06-03 20:13:17 -070018
19 if !s.starts_with('\'') {
David Tolnay51382052017-12-27 13:46:21 -050020 panic!(
21 "lifetime name must start with apostrophe as in \"'a\", \
22 got {:?}",
23 s
24 );
David Tolnay63e3dee2017-06-03 20:13:17 -070025 }
26
27 if s == "'" {
28 panic!("lifetime name must not be empty");
29 }
30
31 if s == "'_" {
32 panic!("\"'_\" is not a valid lifetime name");
33 }
34
35 fn xid_ok(s: &str) -> bool {
36 let mut chars = s.chars();
37 let first = chars.next().unwrap();
38 if !(UnicodeXID::is_xid_start(first) || first == '_') {
39 return false;
40 }
41 for ch in chars {
42 if !UnicodeXID::is_xid_continue(ch) {
43 return false;
44 }
45 }
46 true
47 }
48
49 if !xid_ok(&s[1..]) {
David Tolnaybb4ca9f2017-12-26 12:28:58 -050050 panic!("{:?} is not a valid lifetime name", s);
David Tolnay63e3dee2017-06-03 20:13:17 -070051 }
52
53 Lifetime {
David Tolnay73c98de2017-12-31 15:56:56 -050054 term: term,
David Tolnay63e3dee2017-06-03 20:13:17 -070055 span: span,
56 }
57 }
58}
59
60impl Display for Lifetime {
61 fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
David Tolnay73c98de2017-12-31 15:56:56 -050062 self.term.as_str().fmt(formatter)
David Tolnay63e3dee2017-06-03 20:13:17 -070063 }
64}
65
66impl PartialEq for Lifetime {
67 fn eq(&self, other: &Lifetime) -> bool {
David Tolnay73c98de2017-12-31 15:56:56 -050068 self.term.as_str() == other.term.as_str()
David Tolnay63e3dee2017-06-03 20:13:17 -070069 }
70}
71
72impl Eq for Lifetime {}
73
74impl PartialOrd for Lifetime {
75 fn partial_cmp(&self, other: &Lifetime) -> Option<Ordering> {
76 Some(self.cmp(other))
77 }
78}
79
80impl Ord for Lifetime {
81 fn cmp(&self, other: &Lifetime) -> Ordering {
David Tolnay73c98de2017-12-31 15:56:56 -050082 self.term.as_str().cmp(other.term.as_str())
David Tolnay63e3dee2017-06-03 20:13:17 -070083 }
84}
85
86impl Hash for Lifetime {
87 fn hash<H: Hasher>(&self, h: &mut H) {
David Tolnay73c98de2017-12-31 15:56:56 -050088 self.term.as_str().hash(h)
David Tolnay63e3dee2017-06-03 20:13:17 -070089 }
90}
91
92#[cfg(feature = "parsing")]
93pub mod parsing {
94 use super::*;
David Tolnayc5ab8c62017-12-26 16:43:39 -050095 use synom::Synom;
96 use cursor::Cursor;
David Tolnay203557a2017-12-27 23:59:33 -050097 use parse_error;
98 use synom::PResult;
David Tolnay63e3dee2017-06-03 20:13:17 -070099
100 impl Synom for Lifetime {
101 fn parse(input: Cursor) -> PResult<Self> {
David Tolnay73c98de2017-12-31 15:56:56 -0500102 let (rest, span, term) = match input.term() {
103 Some(term) => term,
David Tolnay63e3dee2017-06-03 20:13:17 -0700104 _ => return parse_error(),
105 };
David Tolnay73c98de2017-12-31 15:56:56 -0500106 if !term.as_str().starts_with('\'') {
David Tolnay63e3dee2017-06-03 20:13:17 -0700107 return parse_error();
108 }
109
David Tolnay51382052017-12-27 13:46:21 -0500110 Ok((
111 rest,
112 Lifetime {
David Tolnay73c98de2017-12-31 15:56:56 -0500113 term: term,
David Tolnay51382052017-12-27 13:46:21 -0500114 span: span,
115 },
116 ))
David Tolnay63e3dee2017-06-03 20:13:17 -0700117 }
Sergio Benitez5680d6a2017-12-29 11:20:29 -0800118
119 fn description() -> Option<&'static str> {
120 Some("lifetime")
121 }
David Tolnay63e3dee2017-06-03 20:13:17 -0700122 }
123}
124
125#[cfg(feature = "printing")]
126mod printing {
127 use super::*;
David Tolnay51382052017-12-27 13:46:21 -0500128 use quote::{ToTokens, Tokens};
129 use proc_macro2::{TokenNode, TokenTree};
David Tolnay63e3dee2017-06-03 20:13:17 -0700130
131 impl ToTokens for Lifetime {
132 fn to_tokens(&self, tokens: &mut Tokens) {
133 tokens.append(TokenTree {
David Tolnay98942562017-12-26 21:24:35 -0500134 span: self.span,
David Tolnay73c98de2017-12-31 15:56:56 -0500135 kind: TokenNode::Term(self.term),
David Tolnay63e3dee2017-06-03 20:13:17 -0700136 })
137 }
138 }
139}