blob: 51f56b923ce5b6024f9b0136bd330af9c6425e2f [file] [log] [blame]
David Tolnayb79ee962016-09-04 09:39:20 -07001use super::*;
2
David Tolnayb79ee962016-09-04 09:39:20 -07003#[derive(Debug, Clone, Eq, PartialEq, Default)]
4pub struct Generics {
5 pub lifetimes: Vec<LifetimeDef>,
6 pub ty_params: Vec<TyParam>,
7 pub where_clause: Vec<WherePredicate>,
8}
9
10#[derive(Debug, Clone, Eq, PartialEq)]
11pub struct Lifetime {
12 pub ident: Ident,
13}
14
15#[derive(Debug, Clone, Eq, PartialEq)]
16pub struct LifetimeDef {
17 pub lifetime: Lifetime,
18 pub bounds: Vec<Lifetime>,
19}
20
21#[derive(Debug, Clone, Eq, PartialEq)]
22pub struct TyParam {
23 pub ident: Ident,
24 pub bounds: Vec<TyParamBound>,
25 pub default: Option<Ty>,
26}
27
28#[derive(Debug, Clone, Eq, PartialEq)]
29pub enum TyParamBound {
30 MaybeSized,
31 Region(Lifetime),
32 Trait(PolyTraitRef),
33}
34
35/// A single predicate in a `where` clause
36#[derive(Debug, Clone, Eq, PartialEq)]
37pub enum WherePredicate {
38 /// A type binding, e.g. `for<'c> Foo: Send+Clone+'c`
39 BoundPredicate(WhereBoundPredicate),
40 /// A lifetime predicate, e.g. `'a: 'b+'c`
41 RegionPredicate(WhereRegionPredicate),
42}
43
44/// A type bound.
45///
46/// E.g. `for<'c> Foo: Send+Clone+'c`
47#[derive(Debug, Clone, Eq, PartialEq)]
48pub struct WhereBoundPredicate {
49 /// Any lifetimes from a `for` binding
50 pub bound_lifetimes: Vec<LifetimeDef>,
51 /// The type being bounded
52 pub bounded_ty: Ty,
53 /// Trait and lifetime bounds (`Clone+Send+'static`)
54 pub bounds: Vec<TyParamBound>,
55}
56
57/// A lifetime predicate.
58///
59/// E.g. `'a: 'b+'c`
60#[derive(Debug, Clone, Eq, PartialEq)]
61pub struct WhereRegionPredicate {
62 pub lifetime: Lifetime,
63 pub bounds: Vec<Lifetime>,
64}
65
David Tolnay86eca752016-09-04 11:26:41 -070066#[cfg(feature = "parsing")]
David Tolnay9d8f1972016-09-04 11:58:48 -070067pub mod parsing {
68 use super::*;
69 use common::parsing::word;
70 use ty::parsing::{ty, poly_trait_ref};
71 use nom::multispace;
72
73 named!(pub generics<&str, Generics>, do_parse!(
74 bracketed: alt!(
75 do_parse!(
76 punct!("<") >>
77 lifetimes: separated_list!(punct!(","), lifetime_def) >>
78 ty_params: opt_vec!(preceded!(
79 cond!(!lifetimes.is_empty(), punct!(",")),
80 separated_nonempty_list!(punct!(","), ty_param)
81 )) >>
82 punct!(">") >>
83 (lifetimes, ty_params)
84 )
85 |
86 epsilon!() => { |_| (Vec::new(), Vec::new()) }
87 ) >>
88 where_clause: opt_vec!(do_parse!(
89 punct!("where") >>
90 multispace >>
91 predicates: separated_nonempty_list!(punct!(","), where_predicate) >>
92 opt!(punct!(",")) >>
93 (predicates)
94 )) >>
95 (Generics {
96 lifetimes: bracketed.0,
97 ty_params: bracketed.1,
98 where_clause: where_clause,
99 })
100 ));
101
102 named!(pub lifetime<&str, Lifetime>, preceded!(
103 punct!("'"),
David Tolnay87d0b442016-09-04 11:52:12 -0700104 map!(word, |ident| Lifetime {
105 ident: format!("'{}", ident),
106 })
David Tolnay9d8f1972016-09-04 11:58:48 -0700107 ));
108
109 named!(pub lifetime_def<&str, LifetimeDef>, do_parse!(
110 life: lifetime >>
111 bounds: opt_vec!(preceded!(
112 punct!(":"),
113 separated_nonempty_list!(punct!(","), lifetime)
114 )) >>
115 (LifetimeDef {
116 lifetime: life,
117 bounds: bounds,
118 })
119 ));
120
121 named!(pub bound_lifetimes<&str, Vec<LifetimeDef> >, opt_vec!(do_parse!(
122 punct!("for") >>
123 punct!("<") >>
124 lifetimes: separated_list!(punct!(","), lifetime_def) >>
125 punct!(">") >>
126 (lifetimes)
127 )));
128
129 named!(ty_param<&str, TyParam>, do_parse!(
130 ident: word >>
131 bounds: opt_vec!(preceded!(
132 punct!(":"),
133 separated_nonempty_list!(punct!("+"), ty_param_bound)
134 )) >>
135 default: opt!(preceded!(
136 punct!("="),
137 ty
138 )) >>
139 (TyParam {
140 ident: ident,
141 bounds: bounds,
142 default: default,
143 })
144 ));
145
146 named!(pub ty_param_bound<&str, TyParamBound>, alt!(
147 tuple!(punct!("?"), punct!("Sized")) => { |_| TyParamBound::MaybeSized }
148 |
149 lifetime => { TyParamBound::Region }
150 |
151 poly_trait_ref => { TyParamBound::Trait }
152 ));
153
154 named!(where_predicate<&str, WherePredicate>, alt!(
David Tolnay6b7aaf02016-09-04 10:39:25 -0700155 do_parse!(
David Tolnay9d8f1972016-09-04 11:58:48 -0700156 ident: lifetime >>
157 punct!(":") >>
158 bounds: separated_nonempty_list!(punct!("+"), lifetime) >>
159 (WherePredicate::RegionPredicate(WhereRegionPredicate {
160 lifetime: ident,
161 bounds: bounds,
162 }))
David Tolnayb79ee962016-09-04 09:39:20 -0700163 )
164 |
David Tolnay9d8f1972016-09-04 11:58:48 -0700165 do_parse!(
166 bound_lifetimes: bound_lifetimes >>
167 bounded_ty: ty >>
168 punct!(":") >>
169 bounds: separated_nonempty_list!(punct!("+"), ty_param_bound) >>
170 (WherePredicate::BoundPredicate(WhereBoundPredicate {
171 bound_lifetimes: bound_lifetimes,
172 bounded_ty: bounded_ty,
173 bounds: bounds,
174 }))
175 )
176 ));
177}
David Tolnay87d0b442016-09-04 11:52:12 -0700178
179#[cfg(feature = "printing")]
180mod printing {
181 use super::*;
182 use quote::{Tokens, ToTokens};
183
184 impl ToTokens for Lifetime {
185 fn to_tokens(&self, tokens: &mut Tokens) {
186 self.ident.to_tokens(tokens);
187 }
188 }
189
190 impl ToTokens for LifetimeDef {
191 fn to_tokens(&self, tokens: &mut Tokens) {
192 self.lifetime.to_tokens(tokens);
193 if !self.bounds.is_empty() {
194 tokens.append(":");
195 for (i, bound) in self.bounds.iter().enumerate() {
196 if i > 0 {
197 tokens.append("+");
198 }
199 bound.to_tokens(tokens);
200 }
201 }
202 }
203 }
204
205 impl ToTokens for TyParamBound {
206 fn to_tokens(&self, tokens: &mut Tokens) {
207 match *self {
208 TyParamBound::MaybeSized => tokens.append("?Sized"),
209 TyParamBound::Region(ref lifetime) => lifetime.to_tokens(tokens),
210 TyParamBound::Trait(ref trait_ref) => trait_ref.to_tokens(tokens),
211 }
212 }
213 }
214}