blob: 56582d21189cf3a60da10168cafc30d5b5fe027c [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
5use proc_macro2::Symbol;
6use unicode_xid::UnicodeXID;
7
8use Span;
9
10#[cfg_attr(feature = "extra-traits", derive(Debug))]
11#[cfg_attr(feature = "clone-impls", derive(Clone))]
12pub struct Lifetime {
13 pub sym: Symbol,
14 pub span: Span,
15}
16
17impl Lifetime {
18 pub fn new(sym: Symbol, span: Span) -> Self {
19 let s = sym.as_str();
20
21 if !s.starts_with('\'') {
22 panic!("lifetime name must start with apostrophe as in \"'a\", \
23 got {:?}",
24 s);
25 }
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..]) {
50 panic!("{:?} is not a valid lifetime name");
51 }
52
53 Lifetime {
54 sym: sym,
55 span: span,
56 }
57 }
58}
59
60impl Display for Lifetime {
61 fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
62 self.sym.as_str().fmt(formatter)
63 }
64}
65
66impl PartialEq for Lifetime {
67 fn eq(&self, other: &Lifetime) -> bool {
68 self.sym.as_str() == other.sym.as_str()
69 }
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 {
82 self.sym.as_str().cmp(other.sym.as_str())
83 }
84}
85
86impl Hash for Lifetime {
87 fn hash<H: Hasher>(&self, h: &mut H) {
88 self.sym.as_str().hash(h)
89 }
90}
91
92#[cfg(feature = "parsing")]
93pub mod parsing {
94 use super::*;
95 use synom::{Synom, PResult, Cursor, parse_error};
96
97 impl Synom for Lifetime {
98 fn parse(input: Cursor) -> PResult<Self> {
99 let (rest, span, sym) = match input.word() {
100 Some(word) => word,
101 _ => return parse_error(),
102 };
103 if !sym.as_str().starts_with('\'') {
104 return parse_error();
105 }
106
107 Ok((rest, Lifetime {
108 sym: sym,
109 span: Span(span),
110 }))
111 }
112 }
113}
114
115#[cfg(feature = "printing")]
116mod printing {
117 use super::*;
118 use quote::{Tokens, ToTokens};
119 use proc_macro2::{TokenTree, TokenKind};
120
121 impl ToTokens for Lifetime {
122 fn to_tokens(&self, tokens: &mut Tokens) {
123 tokens.append(TokenTree {
124 span: self.span.0,
125 kind: TokenKind::Word(self.sym),
126 })
127 }
128 }
129}