blob: 8fceaca3f41d46ef62bccefc8be4a6cda7820df8 [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>,
David Tolnay55337722016-09-11 12:58:56 -07007 pub where_clause: WhereClause,
David Tolnayb79ee962016-09-04 09:39:20 -07008}
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 {
David Tolnay55337722016-09-11 12:58:56 -070030 Trait(PolyTraitRef, TraitBoundModifier),
David Tolnayb79ee962016-09-04 09:39:20 -070031 Region(Lifetime),
David Tolnay55337722016-09-11 12:58:56 -070032}
33
34#[derive(Debug, Copy, Clone, Eq, PartialEq)]
35pub enum TraitBoundModifier {
36 None,
37 Maybe,
38}
39
40#[derive(Debug, Clone, Eq, PartialEq, Default)]
41pub struct WhereClause {
42 pub predicates: Vec<WherePredicate>,
David Tolnayb79ee962016-09-04 09:39:20 -070043}
44
45/// A single predicate in a `where` clause
46#[derive(Debug, Clone, Eq, PartialEq)]
47pub enum WherePredicate {
48 /// A type binding, e.g. `for<'c> Foo: Send+Clone+'c`
49 BoundPredicate(WhereBoundPredicate),
50 /// A lifetime predicate, e.g. `'a: 'b+'c`
51 RegionPredicate(WhereRegionPredicate),
52}
53
54/// A type bound.
55///
56/// E.g. `for<'c> Foo: Send+Clone+'c`
57#[derive(Debug, Clone, Eq, PartialEq)]
58pub struct WhereBoundPredicate {
59 /// Any lifetimes from a `for` binding
60 pub bound_lifetimes: Vec<LifetimeDef>,
61 /// The type being bounded
62 pub bounded_ty: Ty,
63 /// Trait and lifetime bounds (`Clone+Send+'static`)
64 pub bounds: Vec<TyParamBound>,
65}
66
67/// A lifetime predicate.
68///
69/// E.g. `'a: 'b+'c`
70#[derive(Debug, Clone, Eq, PartialEq)]
71pub struct WhereRegionPredicate {
72 pub lifetime: Lifetime,
73 pub bounds: Vec<Lifetime>,
74}
75
David Tolnay86eca752016-09-04 11:26:41 -070076#[cfg(feature = "parsing")]
David Tolnay9d8f1972016-09-04 11:58:48 -070077pub mod parsing {
78 use super::*;
David Tolnay55337722016-09-11 12:58:56 -070079 use ident::parsing::ident;
David Tolnay9d8f1972016-09-04 11:58:48 -070080 use ty::parsing::{ty, poly_trait_ref};
81 use nom::multispace;
82
83 named!(pub generics<&str, Generics>, do_parse!(
David Tolnayf6ccb832016-09-04 15:00:56 -070084 bracketed: alt_complete!(
David Tolnay9d8f1972016-09-04 11:58:48 -070085 do_parse!(
86 punct!("<") >>
87 lifetimes: separated_list!(punct!(","), lifetime_def) >>
88 ty_params: opt_vec!(preceded!(
89 cond!(!lifetimes.is_empty(), punct!(",")),
90 separated_nonempty_list!(punct!(","), ty_param)
91 )) >>
92 punct!(">") >>
93 (lifetimes, ty_params)
94 )
95 |
96 epsilon!() => { |_| (Vec::new(), Vec::new()) }
97 ) >>
David Tolnay55337722016-09-11 12:58:56 -070098 where_clause: where_clause >>
David Tolnay9d8f1972016-09-04 11:58:48 -070099 (Generics {
100 lifetimes: bracketed.0,
101 ty_params: bracketed.1,
102 where_clause: where_clause,
103 })
104 ));
105
106 named!(pub lifetime<&str, Lifetime>, preceded!(
107 punct!("'"),
David Tolnay55337722016-09-11 12:58:56 -0700108 map!(ident, |id| Lifetime {
109 ident: format!("'{}", id).into(),
David Tolnay87d0b442016-09-04 11:52:12 -0700110 })
David Tolnay9d8f1972016-09-04 11:58:48 -0700111 ));
112
113 named!(pub lifetime_def<&str, LifetimeDef>, do_parse!(
114 life: lifetime >>
115 bounds: opt_vec!(preceded!(
116 punct!(":"),
David Tolnayc94c38a2016-09-05 17:02:03 -0700117 separated_nonempty_list!(punct!("+"), lifetime)
David Tolnay9d8f1972016-09-04 11:58:48 -0700118 )) >>
119 (LifetimeDef {
120 lifetime: life,
121 bounds: bounds,
122 })
123 ));
124
125 named!(pub bound_lifetimes<&str, Vec<LifetimeDef> >, opt_vec!(do_parse!(
126 punct!("for") >>
127 punct!("<") >>
128 lifetimes: separated_list!(punct!(","), lifetime_def) >>
129 punct!(">") >>
130 (lifetimes)
131 )));
132
133 named!(ty_param<&str, TyParam>, do_parse!(
David Tolnay55337722016-09-11 12:58:56 -0700134 id: ident >>
David Tolnay9d8f1972016-09-04 11:58:48 -0700135 bounds: opt_vec!(preceded!(
136 punct!(":"),
137 separated_nonempty_list!(punct!("+"), ty_param_bound)
138 )) >>
David Tolnayf6ccb832016-09-04 15:00:56 -0700139 default: option!(preceded!(
David Tolnay9d8f1972016-09-04 11:58:48 -0700140 punct!("="),
141 ty
142 )) >>
143 (TyParam {
David Tolnay55337722016-09-11 12:58:56 -0700144 ident: id,
David Tolnay9d8f1972016-09-04 11:58:48 -0700145 bounds: bounds,
146 default: default,
147 })
148 ));
149
David Tolnayf6ccb832016-09-04 15:00:56 -0700150 named!(pub ty_param_bound<&str, TyParamBound>, alt_complete!(
David Tolnay55337722016-09-11 12:58:56 -0700151 preceded!(punct!("?"), poly_trait_ref) => {
152 |poly| TyParamBound::Trait(poly, TraitBoundModifier::Maybe)
153 }
David Tolnay9d8f1972016-09-04 11:58:48 -0700154 |
155 lifetime => { TyParamBound::Region }
156 |
David Tolnay55337722016-09-11 12:58:56 -0700157 poly_trait_ref => {
158 |poly| TyParamBound::Trait(poly, TraitBoundModifier::None)
159 }
160 ));
161
162 named!(pub where_clause<&str, WhereClause>, alt_complete!(
163 do_parse!(
164 punct!("where") >>
165 multispace >>
166 predicates: separated_nonempty_list!(punct!(","), where_predicate) >>
167 option!(punct!(",")) >>
168 (WhereClause { predicates: predicates })
169 )
170 |
171 epsilon!() => { |_| Default::default() }
David Tolnay9d8f1972016-09-04 11:58:48 -0700172 ));
173
David Tolnayf6ccb832016-09-04 15:00:56 -0700174 named!(where_predicate<&str, WherePredicate>, alt_complete!(
David Tolnay6b7aaf02016-09-04 10:39:25 -0700175 do_parse!(
David Tolnay9d8f1972016-09-04 11:58:48 -0700176 ident: lifetime >>
177 punct!(":") >>
178 bounds: separated_nonempty_list!(punct!("+"), lifetime) >>
179 (WherePredicate::RegionPredicate(WhereRegionPredicate {
180 lifetime: ident,
181 bounds: bounds,
182 }))
David Tolnayb79ee962016-09-04 09:39:20 -0700183 )
184 |
David Tolnay9d8f1972016-09-04 11:58:48 -0700185 do_parse!(
186 bound_lifetimes: bound_lifetimes >>
187 bounded_ty: ty >>
188 punct!(":") >>
189 bounds: separated_nonempty_list!(punct!("+"), ty_param_bound) >>
190 (WherePredicate::BoundPredicate(WhereBoundPredicate {
191 bound_lifetimes: bound_lifetimes,
192 bounded_ty: bounded_ty,
193 bounds: bounds,
194 }))
195 )
196 ));
197}
David Tolnay87d0b442016-09-04 11:52:12 -0700198
199#[cfg(feature = "printing")]
200mod printing {
201 use super::*;
202 use quote::{Tokens, ToTokens};
203
David Tolnay8ef93042016-09-04 14:08:40 -0700204 impl ToTokens for Generics {
205 fn to_tokens(&self, tokens: &mut Tokens) {
206 let has_lifetimes = !self.lifetimes.is_empty();
207 let has_ty_params = !self.ty_params.is_empty();
208 if has_lifetimes || has_ty_params {
209 tokens.append("<");
210 tokens.append_separated(&self.lifetimes, ",");
211 if has_lifetimes && has_ty_params {
212 tokens.append(",");
213 }
214 tokens.append_separated(&self.ty_params, ",");
215 tokens.append(">");
216 }
David Tolnay8ef93042016-09-04 14:08:40 -0700217 }
218 }
219
David Tolnay87d0b442016-09-04 11:52:12 -0700220 impl ToTokens for Lifetime {
221 fn to_tokens(&self, tokens: &mut Tokens) {
222 self.ident.to_tokens(tokens);
223 }
224 }
225
226 impl ToTokens for LifetimeDef {
227 fn to_tokens(&self, tokens: &mut Tokens) {
228 self.lifetime.to_tokens(tokens);
229 if !self.bounds.is_empty() {
230 tokens.append(":");
David Tolnay94ebdf92016-09-04 13:33:16 -0700231 tokens.append_separated(&self.bounds, "+");
David Tolnay87d0b442016-09-04 11:52:12 -0700232 }
233 }
234 }
235
David Tolnay8ef93042016-09-04 14:08:40 -0700236 impl ToTokens for TyParam {
237 fn to_tokens(&self, tokens: &mut Tokens) {
238 self.ident.to_tokens(tokens);
239 if !self.bounds.is_empty() {
240 tokens.append(":");
David Tolnay686b59b2016-09-04 14:39:50 -0700241 tokens.append_separated(&self.bounds, "+");
David Tolnay8ef93042016-09-04 14:08:40 -0700242 }
243 if let Some(ref default) = self.default {
244 tokens.append("=");
245 default.to_tokens(tokens);
246 }
247 }
248 }
249
David Tolnay87d0b442016-09-04 11:52:12 -0700250 impl ToTokens for TyParamBound {
251 fn to_tokens(&self, tokens: &mut Tokens) {
252 match *self {
David Tolnay87d0b442016-09-04 11:52:12 -0700253 TyParamBound::Region(ref lifetime) => lifetime.to_tokens(tokens),
David Tolnay55337722016-09-11 12:58:56 -0700254 TyParamBound::Trait(ref trait_ref, modifier) => {
255 match modifier {
256 TraitBoundModifier::None => {}
257 TraitBoundModifier::Maybe => tokens.append("?"),
258 }
259 trait_ref.to_tokens(tokens);
260 }
261 }
262 }
263 }
264
265 impl ToTokens for WhereClause {
266 fn to_tokens(&self, tokens: &mut Tokens) {
267 if !self.predicates.is_empty() {
268 tokens.append("where");
269 tokens.append_separated(&self.predicates, ",");
David Tolnay87d0b442016-09-04 11:52:12 -0700270 }
271 }
272 }
David Tolnay8ef93042016-09-04 14:08:40 -0700273
274 impl ToTokens for WherePredicate {
275 fn to_tokens(&self, tokens: &mut Tokens) {
276 match *self {
277 WherePredicate::BoundPredicate(ref predicate) => {
278 predicate.to_tokens(tokens);
279 }
280 WherePredicate::RegionPredicate(ref predicate) => {
281 predicate.to_tokens(tokens);
282 }
283 }
284 }
285 }
286
287 impl ToTokens for WhereBoundPredicate {
288 fn to_tokens(&self, tokens: &mut Tokens) {
289 if !self.bound_lifetimes.is_empty() {
290 tokens.append("for");
291 tokens.append("<");
292 tokens.append_separated(&self.bound_lifetimes, ",");
293 tokens.append(">");
294 }
295 self.bounded_ty.to_tokens(tokens);
296 if !self.bounds.is_empty() {
297 tokens.append(":");
298 tokens.append_separated(&self.bounds, "+");
299 }
300 }
301 }
302
303 impl ToTokens for WhereRegionPredicate {
304 fn to_tokens(&self, tokens: &mut Tokens) {
305 self.lifetime.to_tokens(tokens);
306 if !self.bounds.is_empty() {
307 tokens.append(":");
308 tokens.append_separated(&self.bounds, "+");
309 }
310 }
311 }
David Tolnay87d0b442016-09-04 11:52:12 -0700312}