1 use super::*; 2 use crate::punctuated::Punctuated; 3 4 ast_struct! { 5 /// An enum variant. 6 /// 7 /// *This type is available if Syn is built with the `"derive"` or `"full"` 8 /// feature.* 9 pub struct Variant { 10 /// Attributes tagged on the variant. 11 pub attrs: Vec<Attribute>, 12 13 /// Name of the variant. 14 pub ident: Ident, 15 16 /// Content stored in the variant. 17 pub fields: Fields, 18 19 /// Explicit discriminant: `Variant = 1` 20 pub discriminant: Option<(Token![=], Expr)>, 21 } 22 } 23 24 ast_enum_of_structs! { 25 /// Data stored within an enum variant or struct. 26 /// 27 /// *This type is available if Syn is built with the `"derive"` or `"full"` 28 /// feature.* 29 /// 30 /// # Syntax tree enum 31 /// 32 /// This type is a [syntax tree enum]. 33 /// 34 /// [syntax tree enum]: enum.Expr.html#syntax-tree-enums 35 // 36 // TODO: change syntax-tree-enum link to an intra rustdoc link, currently 37 // blocked on https://github.com/rust-lang/rust/issues/62833 38 pub enum Fields { 39 /// Named fields of a struct or struct variant such as `Point { x: f64, 40 /// y: f64 }`. 41 Named(FieldsNamed), 42 43 /// Unnamed fields of a tuple struct or tuple variant such as `Some(T)`. 44 Unnamed(FieldsUnnamed), 45 46 /// Unit struct or unit variant such as `None`. 47 Unit, 48 } 49 } 50 51 ast_struct! { 52 /// Named fields of a struct or struct variant such as `Point { x: f64, 53 /// y: f64 }`. 54 /// 55 /// *This type is available if Syn is built with the `"derive"` or 56 /// `"full"` feature.* 57 pub struct FieldsNamed { 58 pub brace_token: token::Brace, 59 pub named: Punctuated<Field, Token![,]>, 60 } 61 } 62 63 ast_struct! { 64 /// Unnamed fields of a tuple struct or tuple variant such as `Some(T)`. 65 /// 66 /// *This type is available if Syn is built with the `"derive"` or 67 /// `"full"` feature.* 68 pub struct FieldsUnnamed { 69 pub paren_token: token::Paren, 70 pub unnamed: Punctuated<Field, Token![,]>, 71 } 72 } 73 74 impl Fields { 75 /// Get an iterator over the borrowed [`Field`] items in this object. This 76 /// iterator can be used to iterate over a named or unnamed struct or 77 /// variant's fields uniformly. iter(&self) -> punctuated::Iter<Field>78 pub fn iter(&self) -> punctuated::Iter<Field> { 79 match self { 80 Fields::Unit => crate::punctuated::empty_punctuated_iter(), 81 Fields::Named(f) => f.named.iter(), 82 Fields::Unnamed(f) => f.unnamed.iter(), 83 } 84 } 85 86 /// Get an iterator over the mutably borrowed [`Field`] items in this 87 /// object. This iterator can be used to iterate over a named or unnamed 88 /// struct or variant's fields uniformly. iter_mut(&mut self) -> punctuated::IterMut<Field>89 pub fn iter_mut(&mut self) -> punctuated::IterMut<Field> { 90 match self { 91 Fields::Unit => crate::punctuated::empty_punctuated_iter_mut(), 92 Fields::Named(f) => f.named.iter_mut(), 93 Fields::Unnamed(f) => f.unnamed.iter_mut(), 94 } 95 } 96 97 /// Returns the number of fields. len(&self) -> usize98 pub fn len(&self) -> usize { 99 match self { 100 Fields::Unit => 0, 101 Fields::Named(f) => f.named.len(), 102 Fields::Unnamed(f) => f.unnamed.len(), 103 } 104 } 105 106 /// Returns `true` if there are zero fields. is_empty(&self) -> bool107 pub fn is_empty(&self) -> bool { 108 match self { 109 Fields::Unit => true, 110 Fields::Named(f) => f.named.is_empty(), 111 Fields::Unnamed(f) => f.unnamed.is_empty(), 112 } 113 } 114 } 115 116 impl IntoIterator for Fields { 117 type Item = Field; 118 type IntoIter = punctuated::IntoIter<Field>; 119 into_iter(self) -> Self::IntoIter120 fn into_iter(self) -> Self::IntoIter { 121 match self { 122 Fields::Unit => Punctuated::<Field, ()>::new().into_iter(), 123 Fields::Named(f) => f.named.into_iter(), 124 Fields::Unnamed(f) => f.unnamed.into_iter(), 125 } 126 } 127 } 128 129 impl<'a> IntoIterator for &'a Fields { 130 type Item = &'a Field; 131 type IntoIter = punctuated::Iter<'a, Field>; 132 into_iter(self) -> Self::IntoIter133 fn into_iter(self) -> Self::IntoIter { 134 self.iter() 135 } 136 } 137 138 impl<'a> IntoIterator for &'a mut Fields { 139 type Item = &'a mut Field; 140 type IntoIter = punctuated::IterMut<'a, Field>; 141 into_iter(self) -> Self::IntoIter142 fn into_iter(self) -> Self::IntoIter { 143 self.iter_mut() 144 } 145 } 146 147 ast_struct! { 148 /// A field of a struct or enum variant. 149 /// 150 /// *This type is available if Syn is built with the `"derive"` or `"full"` 151 /// feature.* 152 pub struct Field { 153 /// Attributes tagged on the field. 154 pub attrs: Vec<Attribute>, 155 156 /// Visibility of the field. 157 pub vis: Visibility, 158 159 /// Name of the field, if any. 160 /// 161 /// Fields of tuple structs have no names. 162 pub ident: Option<Ident>, 163 164 pub colon_token: Option<Token![:]>, 165 166 /// Type of the field. 167 pub ty: Type, 168 } 169 } 170 171 ast_enum_of_structs! { 172 /// The visibility level of an item: inherited or `pub` or 173 /// `pub(restricted)`. 174 /// 175 /// *This type is available if Syn is built with the `"derive"` or `"full"` 176 /// feature.* 177 /// 178 /// # Syntax tree enum 179 /// 180 /// This type is a [syntax tree enum]. 181 /// 182 /// [syntax tree enum]: enum.Expr.html#syntax-tree-enums 183 // 184 // TODO: change syntax-tree-enum link to an intra rustdoc link, currently 185 // blocked on https://github.com/rust-lang/rust/issues/62833 186 pub enum Visibility { 187 /// A public visibility level: `pub`. 188 Public(VisPublic), 189 190 /// A crate-level visibility: `crate`. 191 Crate(VisCrate), 192 193 /// A visibility level restricted to some path: `pub(self)` or 194 /// `pub(super)` or `pub(crate)` or `pub(in some::module)`. 195 Restricted(VisRestricted), 196 197 /// An inherited visibility, which usually means private. 198 Inherited, 199 } 200 } 201 202 ast_struct! { 203 /// A public visibility level: `pub`. 204 /// 205 /// *This type is available if Syn is built with the `"derive"` or 206 /// `"full"` feature.* 207 pub struct VisPublic { 208 pub pub_token: Token![pub], 209 } 210 } 211 212 ast_struct! { 213 /// A crate-level visibility: `crate`. 214 /// 215 /// *This type is available if Syn is built with the `"derive"` or 216 /// `"full"` feature.* 217 pub struct VisCrate { 218 pub crate_token: Token![crate], 219 } 220 } 221 222 ast_struct! { 223 /// A visibility level restricted to some path: `pub(self)` or 224 /// `pub(super)` or `pub(crate)` or `pub(in some::module)`. 225 /// 226 /// *This type is available if Syn is built with the `"derive"` or 227 /// `"full"` feature.* 228 pub struct VisRestricted { 229 pub pub_token: Token![pub], 230 pub paren_token: token::Paren, 231 pub in_token: Option<Token![in]>, 232 pub path: Box<Path>, 233 } 234 } 235 236 #[cfg(feature = "parsing")] 237 pub mod parsing { 238 use super::*; 239 240 use crate::ext::IdentExt; 241 use crate::parse::{Parse, ParseStream, Result}; 242 243 impl Parse for Variant { parse(input: ParseStream) -> Result<Self>244 fn parse(input: ParseStream) -> Result<Self> { 245 Ok(Variant { 246 attrs: input.call(Attribute::parse_outer)?, 247 ident: input.parse()?, 248 fields: { 249 if input.peek(token::Brace) { 250 Fields::Named(input.parse()?) 251 } else if input.peek(token::Paren) { 252 Fields::Unnamed(input.parse()?) 253 } else { 254 Fields::Unit 255 } 256 }, 257 discriminant: { 258 if input.peek(Token![=]) { 259 let eq_token: Token![=] = input.parse()?; 260 let discriminant: Expr = input.parse()?; 261 Some((eq_token, discriminant)) 262 } else { 263 None 264 } 265 }, 266 }) 267 } 268 } 269 270 impl Parse for FieldsNamed { parse(input: ParseStream) -> Result<Self>271 fn parse(input: ParseStream) -> Result<Self> { 272 let content; 273 Ok(FieldsNamed { 274 brace_token: braced!(content in input), 275 named: content.parse_terminated(Field::parse_named)?, 276 }) 277 } 278 } 279 280 impl Parse for FieldsUnnamed { parse(input: ParseStream) -> Result<Self>281 fn parse(input: ParseStream) -> Result<Self> { 282 let content; 283 Ok(FieldsUnnamed { 284 paren_token: parenthesized!(content in input), 285 unnamed: content.parse_terminated(Field::parse_unnamed)?, 286 }) 287 } 288 } 289 290 impl Field { 291 /// Parses a named (braced struct) field. parse_named(input: ParseStream) -> Result<Self>292 pub fn parse_named(input: ParseStream) -> Result<Self> { 293 Ok(Field { 294 attrs: input.call(Attribute::parse_outer)?, 295 vis: input.parse()?, 296 ident: Some(input.parse()?), 297 colon_token: Some(input.parse()?), 298 ty: input.parse()?, 299 }) 300 } 301 302 /// Parses an unnamed (tuple struct) field. parse_unnamed(input: ParseStream) -> Result<Self>303 pub fn parse_unnamed(input: ParseStream) -> Result<Self> { 304 Ok(Field { 305 attrs: input.call(Attribute::parse_outer)?, 306 vis: input.parse()?, 307 ident: None, 308 colon_token: None, 309 ty: input.parse()?, 310 }) 311 } 312 } 313 314 impl Parse for Visibility { parse(input: ParseStream) -> Result<Self>315 fn parse(input: ParseStream) -> Result<Self> { 316 if input.peek(Token![pub]) { 317 Self::parse_pub(input) 318 } else if input.peek(Token![crate]) { 319 Self::parse_crate(input) 320 } else { 321 Ok(Visibility::Inherited) 322 } 323 } 324 } 325 326 impl Visibility { parse_pub(input: ParseStream) -> Result<Self>327 fn parse_pub(input: ParseStream) -> Result<Self> { 328 let pub_token = input.parse::<Token![pub]>()?; 329 330 if input.peek(token::Paren) { 331 // TODO: optimize using advance_to 332 let ahead = input.fork(); 333 let mut content; 334 parenthesized!(content in ahead); 335 336 if content.peek(Token![crate]) 337 || content.peek(Token![self]) 338 || content.peek(Token![super]) 339 { 340 return Ok(Visibility::Restricted(VisRestricted { 341 pub_token, 342 paren_token: parenthesized!(content in input), 343 in_token: None, 344 path: Box::new(Path::from(content.call(Ident::parse_any)?)), 345 })); 346 } else if content.peek(Token![in]) { 347 return Ok(Visibility::Restricted(VisRestricted { 348 pub_token, 349 paren_token: parenthesized!(content in input), 350 in_token: Some(content.parse()?), 351 path: Box::new(content.call(Path::parse_mod_style)?), 352 })); 353 } 354 } 355 356 Ok(Visibility::Public(VisPublic { pub_token })) 357 } 358 parse_crate(input: ParseStream) -> Result<Self>359 fn parse_crate(input: ParseStream) -> Result<Self> { 360 if input.peek2(Token![::]) { 361 Ok(Visibility::Inherited) 362 } else { 363 Ok(Visibility::Crate(VisCrate { 364 crate_token: input.parse()?, 365 })) 366 } 367 } 368 } 369 } 370 371 #[cfg(feature = "printing")] 372 mod printing { 373 use super::*; 374 375 use proc_macro2::TokenStream; 376 use quote::{ToTokens, TokenStreamExt}; 377 378 use crate::print::TokensOrDefault; 379 380 impl ToTokens for Variant { to_tokens(&self, tokens: &mut TokenStream)381 fn to_tokens(&self, tokens: &mut TokenStream) { 382 tokens.append_all(&self.attrs); 383 self.ident.to_tokens(tokens); 384 self.fields.to_tokens(tokens); 385 if let Some((eq_token, disc)) = &self.discriminant { 386 eq_token.to_tokens(tokens); 387 disc.to_tokens(tokens); 388 } 389 } 390 } 391 392 impl ToTokens for FieldsNamed { to_tokens(&self, tokens: &mut TokenStream)393 fn to_tokens(&self, tokens: &mut TokenStream) { 394 self.brace_token.surround(tokens, |tokens| { 395 self.named.to_tokens(tokens); 396 }); 397 } 398 } 399 400 impl ToTokens for FieldsUnnamed { to_tokens(&self, tokens: &mut TokenStream)401 fn to_tokens(&self, tokens: &mut TokenStream) { 402 self.paren_token.surround(tokens, |tokens| { 403 self.unnamed.to_tokens(tokens); 404 }); 405 } 406 } 407 408 impl ToTokens for Field { to_tokens(&self, tokens: &mut TokenStream)409 fn to_tokens(&self, tokens: &mut TokenStream) { 410 tokens.append_all(&self.attrs); 411 self.vis.to_tokens(tokens); 412 if let Some(ident) = &self.ident { 413 ident.to_tokens(tokens); 414 TokensOrDefault(&self.colon_token).to_tokens(tokens); 415 } 416 self.ty.to_tokens(tokens); 417 } 418 } 419 420 impl ToTokens for VisPublic { to_tokens(&self, tokens: &mut TokenStream)421 fn to_tokens(&self, tokens: &mut TokenStream) { 422 self.pub_token.to_tokens(tokens) 423 } 424 } 425 426 impl ToTokens for VisCrate { to_tokens(&self, tokens: &mut TokenStream)427 fn to_tokens(&self, tokens: &mut TokenStream) { 428 self.crate_token.to_tokens(tokens); 429 } 430 } 431 432 impl ToTokens for VisRestricted { to_tokens(&self, tokens: &mut TokenStream)433 fn to_tokens(&self, tokens: &mut TokenStream) { 434 self.pub_token.to_tokens(tokens); 435 self.paren_token.surround(tokens, |tokens| { 436 // TODO: If we have a path which is not "self" or "super" or 437 // "crate", automatically add the "in" token. 438 self.in_token.to_tokens(tokens); 439 self.path.to_tokens(tokens); 440 }); 441 } 442 } 443 } 444